embulk-input-singer_tap 0.1.0

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 (29) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +38 -0
  5. data/build.gradle +98 -0
  6. data/config/checkstyle/checkstyle.xml +128 -0
  7. data/config/checkstyle/default.xml +108 -0
  8. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  9. data/gradle/wrapper/gradle-wrapper.properties +5 -0
  10. data/gradlew +172 -0
  11. data/gradlew.bat +84 -0
  12. data/lib/embulk/input/singer_tap.rb +3 -0
  13. data/src/main/java/org/embulk/input/singer_tap/ArrayParser.java +31 -0
  14. data/src/main/java/org/embulk/input/singer_tap/BooleanParser.java +16 -0
  15. data/src/main/java/org/embulk/input/singer_tap/IntegerParser.java +16 -0
  16. data/src/main/java/org/embulk/input/singer_tap/NullableArrayParser.java +19 -0
  17. data/src/main/java/org/embulk/input/singer_tap/NullableBooleanParser.java +15 -0
  18. data/src/main/java/org/embulk/input/singer_tap/NullableIntegerParser.java +15 -0
  19. data/src/main/java/org/embulk/input/singer_tap/NullableNumberParser.java +15 -0
  20. data/src/main/java/org/embulk/input/singer_tap/NullableObjectParser.java +21 -0
  21. data/src/main/java/org/embulk/input/singer_tap/NullableStringParser.java +15 -0
  22. data/src/main/java/org/embulk/input/singer_tap/NumberParser.java +16 -0
  23. data/src/main/java/org/embulk/input/singer_tap/ObjectParser.java +52 -0
  24. data/src/main/java/org/embulk/input/singer_tap/ParserGenerator.java +79 -0
  25. data/src/main/java/org/embulk/input/singer_tap/RecordParser.java +11 -0
  26. data/src/main/java/org/embulk/input/singer_tap/SingerTapInputPlugin.java +265 -0
  27. data/src/main/java/org/embulk/input/singer_tap/StringParser.java +16 -0
  28. data/src/test/java/org/embulk/input/singer_tap/TestSingerTapInputPlugin.java +5 -0
  29. metadata +100 -0
data/gradlew.bat ADDED
@@ -0,0 +1,84 @@
1
+ @if "%DEBUG%" == "" @echo off
2
+ @rem ##########################################################################
3
+ @rem
4
+ @rem Gradle startup script for Windows
5
+ @rem
6
+ @rem ##########################################################################
7
+
8
+ @rem Set local scope for the variables with windows NT shell
9
+ if "%OS%"=="Windows_NT" setlocal
10
+
11
+ set DIRNAME=%~dp0
12
+ if "%DIRNAME%" == "" set DIRNAME=.
13
+ set APP_BASE_NAME=%~n0
14
+ set APP_HOME=%DIRNAME%
15
+
16
+ @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17
+ set DEFAULT_JVM_OPTS=
18
+
19
+ @rem Find java.exe
20
+ if defined JAVA_HOME goto findJavaFromJavaHome
21
+
22
+ set JAVA_EXE=java.exe
23
+ %JAVA_EXE% -version >NUL 2>&1
24
+ if "%ERRORLEVEL%" == "0" goto init
25
+
26
+ echo.
27
+ echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28
+ echo.
29
+ echo Please set the JAVA_HOME variable in your environment to match the
30
+ echo location of your Java installation.
31
+
32
+ goto fail
33
+
34
+ :findJavaFromJavaHome
35
+ set JAVA_HOME=%JAVA_HOME:"=%
36
+ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37
+
38
+ if exist "%JAVA_EXE%" goto init
39
+
40
+ echo.
41
+ echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42
+ echo.
43
+ echo Please set the JAVA_HOME variable in your environment to match the
44
+ echo location of your Java installation.
45
+
46
+ goto fail
47
+
48
+ :init
49
+ @rem Get command-line arguments, handling Windows variants
50
+
51
+ if not "%OS%" == "Windows_NT" goto win9xME_args
52
+
53
+ :win9xME_args
54
+ @rem Slurp the command line arguments.
55
+ set CMD_LINE_ARGS=
56
+ set _SKIP=2
57
+
58
+ :win9xME_args_slurp
59
+ if "x%~1" == "x" goto execute
60
+
61
+ set CMD_LINE_ARGS=%*
62
+
63
+ :execute
64
+ @rem Setup the command line
65
+
66
+ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67
+
68
+ @rem Execute Gradle
69
+ "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70
+
71
+ :end
72
+ @rem End local scope for the variables with windows NT shell
73
+ if "%ERRORLEVEL%"=="0" goto mainEnd
74
+
75
+ :fail
76
+ rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77
+ rem the _cmd.exe /c_ return code!
78
+ if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79
+ exit /b 1
80
+
81
+ :mainEnd
82
+ if "%OS%"=="Windows_NT" endlocal
83
+
84
+ :omega
@@ -0,0 +1,3 @@
1
+ Embulk::JavaPlugin.register_input(
2
+ "singer_tap", "org.embulk.input.singer_tap.SingerTapInputPlugin",
3
+ File.expand_path('../../../../classpath', __FILE__))
@@ -0,0 +1,31 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import com.fasterxml.jackson.databind.node.ArrayNode;
5
+ import org.embulk.spi.type.Type;
6
+ import org.embulk.spi.type.Types;
7
+ import org.msgpack.value.Value;
8
+ import org.msgpack.value.ValueFactory;
9
+
10
+ import java.util.ArrayList;
11
+ import java.util.List;
12
+
13
+ public class ArrayParser implements RecordParser {
14
+ private RecordParser elementParser;
15
+
16
+ public ArrayParser(JsonNode node) throws Exception {
17
+ elementParser = ParserGenerator.generateParser(node);
18
+ }
19
+
20
+ public Value parse(JsonNode node) {
21
+ ArrayNode arrNode = (ArrayNode) node;
22
+ List<Value> list = new ArrayList<>();
23
+ for (JsonNode element : arrNode) {
24
+ list.add(elementParser.parse(element));
25
+ }
26
+
27
+ return ValueFactory.newArray(list);
28
+ }
29
+
30
+ public Type embulkType() { return Types.JSON; }
31
+ }
@@ -0,0 +1,16 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.embulk.spi.type.Type;
5
+ import org.embulk.spi.type.Types;
6
+ import org.msgpack.value.Value;
7
+ import org.msgpack.value.ValueFactory;
8
+
9
+ public class BooleanParser implements RecordParser {
10
+ @Override
11
+ public Value parse(JsonNode node) {
12
+ return ValueFactory.newBoolean(node.asBoolean());
13
+ }
14
+
15
+ public Type embulkType() { return Types.BOOLEAN; }
16
+ }
@@ -0,0 +1,16 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.embulk.spi.type.Type;
5
+ import org.embulk.spi.type.Types;
6
+ import org.msgpack.value.Value;
7
+ import org.msgpack.value.ValueFactory;
8
+
9
+ public class IntegerParser implements RecordParser {
10
+ @Override
11
+ public Value parse(JsonNode node) {
12
+ return ValueFactory.newInteger(node.asLong());
13
+ }
14
+
15
+ public Type embulkType() { return Types.LONG; }
16
+ }
@@ -0,0 +1,19 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.msgpack.value.Value;
5
+ import org.msgpack.value.ValueFactory;
6
+
7
+ public class NullableArrayParser extends ArrayParser {
8
+ public NullableArrayParser(JsonNode node) throws Exception {
9
+ super(node);
10
+ }
11
+
12
+ @Override
13
+ public Value parse(JsonNode node) {
14
+ if (node.isNull()) {
15
+ return ValueFactory.newNil();
16
+ }
17
+ return super.parse(node);
18
+ }
19
+ }
@@ -0,0 +1,15 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.msgpack.value.Value;
5
+ import org.msgpack.value.ValueFactory;
6
+
7
+ public class NullableBooleanParser extends BooleanParser {
8
+ @Override
9
+ public Value parse(JsonNode node) {
10
+ if (node.isNull()) {
11
+ return ValueFactory.newNil();
12
+ }
13
+ return ValueFactory.newBoolean(node.asBoolean());
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.msgpack.value.Value;
5
+ import org.msgpack.value.ValueFactory;
6
+
7
+ public class NullableIntegerParser extends IntegerParser {
8
+ @Override
9
+ public Value parse(JsonNode node) {
10
+ if (node.isNull()) {
11
+ return ValueFactory.newNil();
12
+ }
13
+ return ValueFactory.newInteger(node.asLong());
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.msgpack.value.Value;
5
+ import org.msgpack.value.ValueFactory;
6
+
7
+ public class NullableNumberParser extends NumberParser {
8
+ @Override
9
+ public Value parse(JsonNode node) {
10
+ if (node.isNull()) {
11
+ return ValueFactory.newNil();
12
+ }
13
+ return ValueFactory.newFloat(node.asDouble());
14
+ }
15
+ }
@@ -0,0 +1,21 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import com.fasterxml.jackson.databind.node.ObjectNode;
5
+ import org.msgpack.value.Value;
6
+ import org.msgpack.value.ValueFactory;
7
+
8
+ public class NullableObjectParser extends ObjectParser {
9
+ public NullableObjectParser(ObjectNode node) throws Exception {
10
+ super(node);
11
+ }
12
+
13
+ @Override
14
+ public Value parse(JsonNode node) {
15
+ if (node.isNull()) {
16
+ return ValueFactory.newNil();
17
+ }
18
+ return super.parse(node);
19
+ }
20
+
21
+ }
@@ -0,0 +1,15 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.msgpack.value.Value;
5
+ import org.msgpack.value.ValueFactory;
6
+
7
+ public class NullableStringParser extends StringParser {
8
+ @Override
9
+ public Value parse(JsonNode node) {
10
+ if (node.isNull()) {
11
+ return ValueFactory.newNil();
12
+ }
13
+ return ValueFactory.newString(node.asText());
14
+ }
15
+ }
@@ -0,0 +1,16 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.embulk.spi.type.Type;
5
+ import org.embulk.spi.type.Types;
6
+ import org.msgpack.value.Value;
7
+ import org.msgpack.value.ValueFactory;
8
+
9
+ public class NumberParser implements RecordParser {
10
+ @Override
11
+ public Value parse(JsonNode node) {
12
+ return ValueFactory.newFloat(node.asDouble());
13
+ }
14
+
15
+ public Type embulkType() { return Types.DOUBLE; }
16
+ }
@@ -0,0 +1,52 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import com.fasterxml.jackson.databind.node.ObjectNode;
5
+ import org.embulk.spi.type.Type;
6
+ import org.embulk.spi.type.Types;
7
+ import org.msgpack.value.Value;
8
+ import org.msgpack.value.ValueFactory;
9
+
10
+ import java.util.HashMap;
11
+ import java.util.Iterator;
12
+ import java.util.LinkedHashMap;
13
+ import java.util.Map;
14
+
15
+ public class ObjectParser implements RecordParser {
16
+ private Map<String, RecordParser> fieldParser;
17
+
18
+ public ObjectParser(ObjectNode node) throws Exception {
19
+ fieldParser = new LinkedHashMap<>();
20
+ for (Iterator<Map.Entry<String, JsonNode>> it = node.fields(); it.hasNext(); ) {
21
+ Map.Entry<String, JsonNode> e = it.next();
22
+ fieldParser.put(e.getKey(), ParserGenerator.generateParser(e.getValue()));
23
+ }
24
+ }
25
+
26
+ @Override
27
+ public Value parse(JsonNode node) {
28
+ ObjectNode objNode = (ObjectNode) node;
29
+ Map<Value, Value> map = new HashMap<>();
30
+
31
+ for (Map.Entry<String, RecordParser> entry : fieldParser.entrySet()) {
32
+ String key = entry.getKey();
33
+ JsonNode valNode = objNode.get(key);
34
+ Value val;
35
+ if (valNode == null) {
36
+ val = ValueFactory.newNil();
37
+ }
38
+ else {
39
+ val = fieldParser.get(key).parse(valNode);
40
+ }
41
+ map.put(ValueFactory.newString(key), val);
42
+ }
43
+
44
+ return ValueFactory.newMap(map);
45
+ }
46
+
47
+ public Map<String, RecordParser> properties() {
48
+ return fieldParser;
49
+ }
50
+
51
+ public Type embulkType() { return Types.JSON; }
52
+ }
@@ -0,0 +1,79 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import com.fasterxml.jackson.databind.node.ArrayNode;
5
+ import com.fasterxml.jackson.databind.node.ObjectNode;
6
+
7
+ public class ParserGenerator {
8
+ public static RecordParser generateParser(JsonNode node) throws Exception {
9
+ String type;
10
+ Boolean nullable = false;
11
+ JsonNode type_node = node.get("type");
12
+ if (type_node.isTextual()) {
13
+ type = type_node.asText();
14
+ }
15
+ else if (type_node.isArray()) {
16
+ ArrayNode types = (ArrayNode) type_node;
17
+ int len = types.size();
18
+ if (len == 2) {
19
+ String type_0 = types.get(0).asText();
20
+ String type_1 = types.get(1).asText();
21
+ if (type_0.equals("null")) {
22
+ nullable = true;
23
+ type = type_1;
24
+ }
25
+ else if (type_1.equals("null")) {
26
+ nullable = true;
27
+ type = type_0;
28
+ }
29
+ else {
30
+ type = "undefined";
31
+ }
32
+ }
33
+ else if (len == 1){
34
+ type = types.get(0).asText();
35
+ }
36
+ else {
37
+ throw new Exception("number of possible types must be 1 or 2!");
38
+ }
39
+ }
40
+ else {
41
+ throw new Exception("invalid type!");
42
+ }
43
+
44
+ if (nullable) {
45
+ switch (type) {
46
+ case "string":
47
+ return new NullableStringParser();
48
+ case "number":
49
+ return new NumberParser();
50
+ case "integer":
51
+ return new NullableIntegerParser();
52
+ case "boolean":
53
+ return new NullableBooleanParser();
54
+ case "object":
55
+ return new NullableObjectParser((ObjectNode) (node.get("properties")));
56
+ case "array":
57
+ return new NullableArrayParser(node.get("items"));
58
+ default:
59
+ throw new Exception("Undefined type");
60
+ }
61
+ }
62
+ switch (type) {
63
+ case "string":
64
+ return new StringParser();
65
+ case "number":
66
+ return new NumberParser();
67
+ case "integer":
68
+ return new IntegerParser();
69
+ case "boolean":
70
+ return new BooleanParser();
71
+ case "object":
72
+ return new ObjectParser((ObjectNode) (node.get("properties")));
73
+ case "array":
74
+ return new ArrayParser(node.get("items"));
75
+ default:
76
+ throw new Exception("Undefined type");
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,11 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import org.embulk.spi.type.Type;
5
+ import org.msgpack.value.Value;
6
+
7
+
8
+ public interface RecordParser {
9
+ Value parse(JsonNode node);
10
+ Type embulkType();
11
+ }
@@ -0,0 +1,265 @@
1
+ package org.embulk.input.singer_tap;
2
+
3
+ import java.io.*;
4
+ import java.util.*;
5
+
6
+ import com.fasterxml.jackson.databind.JsonNode;
7
+ import com.fasterxml.jackson.databind.ObjectMapper;
8
+
9
+ import org.embulk.config.*;
10
+ import org.embulk.spi.*;
11
+ import org.msgpack.value.Value;
12
+
13
+
14
+ public class SingerTapInputPlugin
15
+ implements InputPlugin
16
+ {
17
+ public interface PluginTask
18
+ extends Task
19
+ {
20
+ @Config("tap_command")
21
+ public String getTapCommand();
22
+
23
+ @Config("config")
24
+ public String getConfig();
25
+
26
+ @Config("catalog")
27
+ @ConfigDefault("null")
28
+ public Optional<String> getCatalog();
29
+
30
+ @Config("properties")
31
+ @ConfigDefault("null")
32
+ public Optional<String> getProperties();
33
+
34
+ @Config("input_state")
35
+ @ConfigDefault("null")
36
+ public Optional<String> getInputState();
37
+
38
+ @Config("output_state")
39
+ @ConfigDefault("null")
40
+ public Optional<String> getOutputState();
41
+
42
+ String getSchemaFileName();
43
+ void setSchemaFileName(String schemaFile);
44
+
45
+ List<String> getCommandLine();
46
+ void setCommandLine(List<String> commandLine);
47
+
48
+ @ConfigInject
49
+ BufferAllocator getBufferAllocator();
50
+
51
+ }
52
+
53
+ @Override
54
+ public ConfigDiff transaction(ConfigSource config,
55
+ InputPlugin.Control control)
56
+ {
57
+ PluginTask task = config.loadConfig(PluginTask.class);
58
+
59
+ String command = task.getTapCommand() + " --config " + task.getConfig();
60
+
61
+ File schemaFile;
62
+ if (task.getCatalog().isPresent()) {
63
+ if (task.getProperties().isPresent()) {
64
+ throw new ConfigException("only one of 'catalog' or 'properties' parameter is needed");
65
+ }
66
+ String schemaFileName = task.getCatalog().get();
67
+ schemaFile = new File(schemaFileName);
68
+ task.setSchemaFileName(schemaFileName);
69
+ command = command + " --catalog " + schemaFileName;
70
+ }
71
+ else {
72
+ if (!task.getProperties().isPresent()) {
73
+ throw new ConfigException("'catalog' or 'properties' parameter is needed");
74
+ }
75
+ String schemaFileName = task.getProperties().get();
76
+ schemaFile = new File(schemaFileName);
77
+ task.setSchemaFileName(schemaFileName);
78
+ command = command + " --properties " + schemaFileName;
79
+ }
80
+ Schema schema = generateSchema(schemaFile);
81
+
82
+ if (task.getInputState().isPresent()) {
83
+ String stateFileName = task.getInputState().get();
84
+ command = command + " --state " + stateFileName;
85
+ }
86
+
87
+ List<String> cmdline = new ArrayList<>(Arrays.asList("sh", "-c"));
88
+ cmdline.add(command);
89
+ task.setCommandLine(cmdline);
90
+
91
+ int taskCount = 1; // number of run() method calls
92
+
93
+ return resume(task.dump(), schema, taskCount, control);
94
+ }
95
+
96
+ @Override
97
+ public ConfigDiff resume(TaskSource taskSource,
98
+ Schema schema, int taskCount,
99
+ InputPlugin.Control control)
100
+ {
101
+ control.run(taskSource, schema, taskCount);
102
+ return Exec.newConfigDiff();
103
+ }
104
+
105
+ @Override
106
+ public void cleanup(TaskSource taskSource,
107
+ Schema schema, int taskCount,
108
+ List<TaskReport> successTaskReports)
109
+ {
110
+ }
111
+
112
+ @Override
113
+ public TaskReport run(TaskSource taskSource,
114
+ Schema schema, int taskIndex,
115
+ PageOutput output)
116
+ {
117
+ PluginTask task = taskSource.loadTask(PluginTask.class);
118
+ BufferAllocator allocator = task.getBufferAllocator();
119
+
120
+ RecordParser parser;
121
+ try {
122
+ JsonNode schemaNode = getSchema(new File(task.getSchemaFileName()));
123
+ parser = ParserGenerator.generateParser(schemaNode);
124
+ }
125
+ catch (Exception e) {
126
+ throw new ConfigException(e.getMessage());
127
+ }
128
+
129
+ List<String> cmdline = task.getCommandLine();
130
+ ProcessBuilder pb = new ProcessBuilder(cmdline);
131
+ pb.redirectError(ProcessBuilder.Redirect.INHERIT);
132
+ String state = "";
133
+ try {
134
+ Process process = pb.start();
135
+ InputStream stream = process.getInputStream();
136
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
137
+ String line;
138
+ JsonNode root;
139
+ PageBuilder pageBuilder = new PageBuilder(allocator, schema, output);;
140
+ ObjectMapper recordMapper = new ObjectMapper();
141
+ while ((line = br.readLine()) != null) {
142
+ root = recordMapper.readTree(line);
143
+ String type = root.get("type").asText();
144
+ if (type.equals("RECORD")) {
145
+ JsonNode recordNode = root.get("record");
146
+ Value record = parser.parse(recordNode);
147
+ if (!(record.isMapValue())) {
148
+ throw new DataException("invalid record");
149
+ }
150
+ Map<String, Value> rec = new HashMap<>();
151
+ for (Map.Entry<Value, Value> entry : record.asMapValue().entrySet()) {
152
+ rec.put(entry.getKey().asStringValue().asString(), entry.getValue());
153
+ }
154
+ for (Column column : pageBuilder.getSchema().getColumns()) {
155
+ setColumn(column, rec, pageBuilder);
156
+ }
157
+ pageBuilder.addRecord();
158
+ }
159
+ else if (type.equals("SCHEMA")) {
160
+
161
+ }
162
+ else if (type.equals("STATE")) {
163
+ state = root.get("value").toString();
164
+ }
165
+ else {
166
+ throw new DataException("invalid message type: " + type);
167
+ }
168
+ }
169
+ pageBuilder.finish();
170
+ }
171
+ }
172
+ catch (IOException e) {
173
+ throw new DataException(e.getMessage());
174
+ }
175
+ finally {
176
+ if (task.getOutputState().isPresent()) {
177
+ String statePath = task.getOutputState().get();
178
+ try (FileOutputStream writer = new FileOutputStream(statePath)) {
179
+ writer.write(state.getBytes());
180
+ }
181
+ catch (Exception e) {
182
+ throw new DataException(e.getMessage());
183
+ }
184
+ }
185
+ }
186
+
187
+ return Exec.newTaskReport();
188
+ }
189
+
190
+ @Override
191
+ public ConfigDiff guess(ConfigSource config)
192
+ {
193
+ return Exec.newConfigDiff();
194
+ }
195
+
196
+ private JsonNode getSchema(File catalog) {
197
+ ObjectMapper mapper = new ObjectMapper();
198
+ try {
199
+ JsonNode streams = mapper.readTree(catalog).get("streams");
200
+ JsonNode schemaNode = null;
201
+ for (JsonNode stream : streams) {
202
+ JsonNode schema = stream.get("schema");
203
+ JsonNode selected = schema.get("selected");
204
+ if (selected != null && selected.asBoolean()) {
205
+ schemaNode = schema;
206
+ break;
207
+ }
208
+ }
209
+ if (schemaNode == null) {
210
+ throw new ConfigException("schema not selected");
211
+ }
212
+ return schemaNode;
213
+ }
214
+ catch (Exception e) {
215
+ throw new ConfigException(e.getMessage());
216
+ }
217
+ }
218
+
219
+ private Schema generateSchema(File catalog) throws ConfigException {
220
+ Schema.Builder builder = Schema.builder();
221
+ try {
222
+ JsonNode schemaNode = getSchema(catalog);
223
+ RecordParser parser = ParserGenerator.generateParser(schemaNode);
224
+ if (!(parser instanceof ObjectParser)) {
225
+ throw new DataException("invalid schema");
226
+ }
227
+ ObjectParser toplevelParser = (ObjectParser) parser;
228
+ for (Map.Entry<String, RecordParser> entry : toplevelParser.properties().entrySet()) {
229
+ String colName = entry.getKey();
230
+ RecordParser colParser = entry.getValue();
231
+ builder.add(colName, colParser.embulkType());
232
+ }
233
+ }
234
+ catch (Exception e) {
235
+ throw new ConfigException(e.getMessage());
236
+ }
237
+ return builder.build();
238
+ }
239
+
240
+ private void setColumn(Column column, Map<String, Value> mapValue, PageBuilder pageBuilder) {
241
+ String key = column.getName();
242
+ Value val = mapValue.get(key);
243
+ if (val.isStringValue()) {
244
+ pageBuilder.setString(column, val.asStringValue().asString());
245
+ }
246
+ else if (val.isIntegerValue()) {
247
+ pageBuilder.setLong(column, val.asIntegerValue().asLong());
248
+ }
249
+ else if (val.isFloatValue()) {
250
+ pageBuilder.setDouble(column, val.asFloatValue().toDouble());
251
+ }
252
+ else if (val.isBooleanValue()) {
253
+ pageBuilder.setBoolean(column, val.asBooleanValue().getBoolean());
254
+ }
255
+ else if (val.isMapValue() || val.isArrayValue()) {
256
+ pageBuilder.setJson(column, val);
257
+ }
258
+ else if (val.isNilValue()) {
259
+ pageBuilder.setNull(column);
260
+ }
261
+ else {
262
+ throw new DataException("invalid type of record for column: " + key + ": "+ val.getValueType());
263
+ }
264
+ }
265
+ }