embulk-input-athena 0.1.0 → 0.1.6

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/README.md +21 -9
  4. data/build.gradle +22 -11
  5. data/docker-compose.yml +7 -1
  6. data/src/main/java/org/embulk/input/athena/AthenaInputConnection.java +3 -0
  7. data/src/main/java/org/embulk/input/athena/AthenaInputPlugin.java +182 -33
  8. data/src/main/resources/log4j.properties +4 -0
  9. metadata +25 -49
  10. data/src/main/java/org/embulk/input/athena/AthenaInputPlugin.java.tmp1 +0 -192
  11. data/src/main/java/org/embulk/input/jdbc/AbstractJdbcInputPlugin.java +0 -674
  12. data/src/main/java/org/embulk/input/jdbc/JdbcColumn.java +0 -58
  13. data/src/main/java/org/embulk/input/jdbc/JdbcColumnOption.java +0 -31
  14. data/src/main/java/org/embulk/input/jdbc/JdbcInputConnection.java +0 -397
  15. data/src/main/java/org/embulk/input/jdbc/JdbcLiteral.java +0 -38
  16. data/src/main/java/org/embulk/input/jdbc/JdbcSchema.java +0 -55
  17. data/src/main/java/org/embulk/input/jdbc/Ssl.java +0 -37
  18. data/src/main/java/org/embulk/input/jdbc/ToString.java +0 -54
  19. data/src/main/java/org/embulk/input/jdbc/ToStringMap.java +0 -35
  20. data/src/main/java/org/embulk/input/jdbc/getter/AbstractColumnGetter.java +0 -105
  21. data/src/main/java/org/embulk/input/jdbc/getter/AbstractIncrementalHandler.java +0 -45
  22. data/src/main/java/org/embulk/input/jdbc/getter/AbstractTimestampColumnGetter.java +0 -38
  23. data/src/main/java/org/embulk/input/jdbc/getter/BigDecimalColumnGetter.java +0 -59
  24. data/src/main/java/org/embulk/input/jdbc/getter/BooleanColumnGetter.java +0 -56
  25. data/src/main/java/org/embulk/input/jdbc/getter/ColumnGetter.java +0 -21
  26. data/src/main/java/org/embulk/input/jdbc/getter/ColumnGetterFactory.java +0 -207
  27. data/src/main/java/org/embulk/input/jdbc/getter/DateColumnGetter.java +0 -37
  28. data/src/main/java/org/embulk/input/jdbc/getter/DoubleColumnGetter.java +0 -66
  29. data/src/main/java/org/embulk/input/jdbc/getter/FloatColumnGetter.java +0 -66
  30. data/src/main/java/org/embulk/input/jdbc/getter/JsonColumnGetter.java +0 -57
  31. data/src/main/java/org/embulk/input/jdbc/getter/LongColumnGetter.java +0 -70
  32. data/src/main/java/org/embulk/input/jdbc/getter/StringColumnGetter.java +0 -96
  33. data/src/main/java/org/embulk/input/jdbc/getter/TimeColumnGetter.java +0 -37
  34. data/src/main/java/org/embulk/input/jdbc/getter/TimestampColumnGetter.java +0 -36
  35. data/src/main/java/org/embulk/input/jdbc/getter/TimestampWithTimeZoneIncrementalHandler.java +0 -83
  36. data/src/main/java/org/embulk/input/jdbc/getter/TimestampWithoutTimeZoneIncrementalHandler.java +0 -75
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3fb336d83e38770353f87f111859738619bb3e6
4
- data.tar.gz: 7fe07d1b0fd72c8e08ba963e21b590c26242da79
3
+ metadata.gz: df05f5540bab30f61316b799b7cb80b849da32d6
4
+ data.tar.gz: 0a854b7fc362bdff91f8423bd788a119426a4ff0
5
5
  SHA512:
6
- metadata.gz: 4483e0985f1741775a6abbf8a9183231be12f52b5f28dc278c850fbf926fba5a2090e9fd660fd6d5b93782dec551b644828e6b767c096254ccc269deb755728f
7
- data.tar.gz: bb989515c90ebdd73c651099fcfe6b136d1bfcdc1a5c30c979bbb5f0b3e2d782b8212110cb282f3129888bd347cc6e9878ae5ab2deb4118d108d58201a765f2c
6
+ metadata.gz: b84f7b31683d9d239bd41bde61d35ee9d003fe5d0537b96b9f06310ac9123a752288197b671d7d11d335a215bb9334a4589013d9ac65d7cddef3cd033d53371f
7
+ data.tar.gz: c6ea2231c7e1dc107f89b4d0fdf3ba1ee7e495b1be14de86e3c75782fb2219b0818fa094e3d14ac23a492748b7acc5a5781e4ed798ed2a41115b8a783c3f1ca6
data/.gitignore CHANGED
@@ -10,4 +10,5 @@ build/
10
10
  /.metadata/
11
11
  .classpath
12
12
  .project
13
- bin
13
+ bin/
14
+ .vscode/
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Athena input plugin for Embulk
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/embulk-input-athena.svg)](https://badge.fury.io/rb/embulk-input-athena)
4
+ [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
5
+
3
6
  Athena input plugin for Embulk loads records from Athena(AWS).
4
7
 
5
8
  ## Overview
@@ -11,14 +14,16 @@ Athena input plugin for Embulk loads records from Athena(AWS).
11
14
 
12
15
  ## Configuration
13
16
 
14
- * **database**: description (string, required)
15
- * **athena_url**: description (string, required)
16
- * **s3_staging_dir**: description (string, required)
17
- * **access_key**: description (string, required)
18
- * **secret_key**: description (string, required)
19
- * **query**: description (string, required)
20
- * **columns**: description (string, required)
21
- * **options**: description (string, default: {})
17
+ * **driver_path**: path to the jar file of the Athena JDBC driver. If not set, the bundled JDBC driver(AthenaJDBC41-1.1.0.jar) will be used. (string)
18
+ * **database**: database name (string, required)
19
+ * **athena_url**: Athena url (string, required)
20
+ * **s3_staging_dir**: The S3 location to which your query output is written, for example s3://query-results-bucket/folder/. (string, required)
21
+ * **access_key**: AWS access key (string, required)
22
+ * **secret_key**: AWS secret key (string, required)
23
+ * **query**: SQL to run (string, required)
24
+ * **columns**: columns (string, required)
25
+ * **options**: extra JDBC properties (string, default: {})
26
+ * **null_to_zero**: if true, convert long, double and boolean value from null to zero (boolean, default: false)
22
27
 
23
28
  ## Example
24
29
 
@@ -35,12 +40,19 @@ in:
35
40
  columns:
36
41
  - {name: uid, type: string}
37
42
  - {name: created_at, type: timestamp}
43
+ null_to_zero: true
38
44
  ```
39
45
 
40
46
  ## Build
41
47
 
42
- ```
48
+ ```bash
43
49
  $ docker-compose up -d
44
50
  $ docker-compose exec embulk bash
45
51
  embulk>$ ./gradlew gem # -t to watch change of files and rebuild continuously
52
+
53
+ embulk>$ embulk preview -I lib sample.yml
54
+ embulk>$ embulk preview -L . sample.yml
55
+
56
+ curl -u shinji19 https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
57
+ embulk>$ ./gradlew gemPush
46
58
  ```
data/build.gradle CHANGED
@@ -1,21 +1,22 @@
1
1
  plugins {
2
2
  id "com.jfrog.bintray" version "1.1"
3
- id "com.github.jruby-gradle.base" version "0.1.5"
3
+ id "com.github.jruby-gradle.base" version "1.5.0"
4
4
  id "java"
5
5
  id "checkstyle"
6
+ // for task download
7
+ id "de.undercouch.download" version "3.4.2"
6
8
  }
7
9
  import com.github.jrubygradle.JRubyExec
8
10
  repositories {
9
11
  mavenCentral()
10
12
  jcenter()
11
- // for athena jdbc
12
- maven { url "https://maven.atlassian.com/repository/public" }
13
+ maven { url "https://dl.bintray.com/embulk-input-jdbc/maven" }
13
14
  }
14
15
  configurations {
15
16
  provided
16
17
  }
17
18
 
18
- version = "0.1.0"
19
+ version = "0.1.6"
19
20
 
20
21
  sourceCompatibility = 1.8
21
22
  targetCompatibility = 1.8
@@ -23,16 +24,24 @@ targetCompatibility = 1.8
23
24
  dependencies {
24
25
  compile "org.embulk:embulk-core:0.8.39"
25
26
  provided "org.embulk:embulk-core:0.8.39"
26
- // https://mvnrepository.com/artifact/com.amazonaws.athena.jdbc/AthenaJDBC41
27
- // compile group: 'com.amazonaws.athena.jdbc', name: 'AthenaJDBC41', version: '1.0.1-atlassian-hosted'
27
+ // TODO: maven...
28
28
  compile files ('build/AthenaJDBC41-1.1.0.jar')
29
29
  compile group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.301'
30
+ // compile group: 'com.amazonaws', name: 'aws-java-sdk-athena', version: '1.11.301'
31
+ compile 'org.embulk.input.jdbc:embulk-input-jdbc:0.9.1'
30
32
  testCompile "junit:junit:4.+"
31
33
  }
32
34
 
33
- task classpath(type: Copy, dependsOn: ["jar"]) {
35
+ task downloadFile(type: Download) {
36
+ src 'https://s3.amazonaws.com/athena-downloads/drivers/AthenaJDBC41-1.1.0.jar'
37
+ dest buildDir
38
+ onlyIfModified true
39
+ }
40
+
41
+ task classpath(type: Copy, dependsOn: ["downloadFile", "jar"]) {
34
42
  doFirst { file("classpath").deleteDir() }
35
43
  from (configurations.runtime - configurations.provided + files(jar.archivePath))
44
+ from ("build/AthenaJDBC41-1.1.0.jar'")
36
45
  into "classpath"
37
46
  }
38
47
  clean { delete "classpath" }
@@ -55,14 +64,16 @@ task checkstyle(type: Checkstyle) {
55
64
  }
56
65
 
57
66
  task gem(type: JRubyExec, dependsOn: ["gemspec", "classpath"]) {
58
- jrubyArgs "-rrubygems/gem_runner", "-eGem::GemRunner.new.run(ARGV)", "build"
59
- script "${project.name}.gemspec"
67
+ jrubyArgs "-S"
68
+ script "gem"
69
+ scriptArgs "build", "${project.name}.gemspec"
60
70
  doLast { ant.move(file: "${project.name}-${project.version}.gem", todir: "pkg") }
61
71
  }
62
72
 
63
73
  task gemPush(type: JRubyExec, dependsOn: ["gem"]) {
64
- jrubyArgs "-rrubygems/gem_runner", "-eGem::GemRunner.new.run(ARGV)", "push"
65
- script "pkg/${project.name}-${project.version}.gem"
74
+ jrubyArgs "-S"
75
+ script "gem"
76
+ scriptArgs "push", "pkg/${project.name}-${project.version}.gem"
66
77
  }
67
78
 
68
79
  task "package"(dependsOn: ["gemspec", "classpath"]) {
data/docker-compose.yml CHANGED
@@ -7,4 +7,10 @@ services:
7
7
  working_dir: /root/embulk-input-athena
8
8
  volumes:
9
9
  - ./:/root/embulk-input-athena
10
- command: tail -f /dev/null
10
+ tty: true
11
+ postgres:
12
+ image: postgres
13
+ ports:
14
+ - 5432:5432
15
+ environment:
16
+ - POSTGRES_PASSWORD=postgres
@@ -1,3 +1,4 @@
1
+ /*
1
2
  package org.embulk.input.athena;
2
3
 
3
4
  import java.util.List;
@@ -17,6 +18,7 @@ public class AthenaInputConnection
17
18
  throws SQLException
18
19
  {
19
20
  super(connection, null);
21
+ connection.setAutoCommit(true);
20
22
  }
21
23
 
22
24
  @Override
@@ -47,3 +49,4 @@ public class AthenaInputConnection
47
49
  return new SingleSelect(stmt);
48
50
  }
49
51
  }
52
+ */
@@ -1,9 +1,17 @@
1
1
  package org.embulk.input.athena;
2
2
 
3
+ import com.google.common.base.Optional;
4
+
5
+ import java.io.File;
6
+ import java.io.FileFilter;
7
+ import java.net.MalformedURLException;
8
+ import java.net.URISyntaxException;
9
+ import java.net.URL;
10
+ import java.nio.file.Path;
11
+ import java.nio.file.Paths;
3
12
  import java.sql.Connection;
4
13
  import java.sql.DriverManager;
5
14
  import java.sql.ResultSet;
6
- import java.sql.ResultSetMetaData;
7
15
  import java.sql.SQLException;
8
16
  import java.sql.Statement;
9
17
  import java.util.List;
@@ -12,12 +20,14 @@ import java.util.Properties;
12
20
  import org.embulk.config.Config;
13
21
  import org.embulk.config.ConfigDefault;
14
22
  import org.embulk.config.ConfigDiff;
23
+ import org.embulk.config.ConfigException;
15
24
  import org.embulk.config.ConfigInject;
16
25
  import org.embulk.config.ConfigSource;
17
26
  import org.embulk.config.Task;
18
27
  import org.embulk.config.TaskReport;
19
28
  import org.embulk.config.TaskSource;
20
29
  import org.embulk.input.jdbc.ToStringMap;
30
+ import org.embulk.plugin.PluginClassLoader;
21
31
  import org.embulk.spi.BufferAllocator;
22
32
  import org.embulk.spi.Column;
23
33
  import org.embulk.spi.ColumnVisitor;
@@ -28,9 +38,18 @@ import org.embulk.spi.PageOutput;
28
38
  import org.embulk.spi.Schema;
29
39
  import org.embulk.spi.SchemaConfig;
30
40
  import org.embulk.spi.time.Timestamp;
41
+ import org.slf4j.Logger;
42
+
43
+ public class AthenaInputPlugin implements InputPlugin
44
+ {
45
+ protected final Logger logger = Exec.getLogger(getClass());
46
+
47
+ public interface PluginTask extends Task
48
+ {
49
+ @Config("driver_path")
50
+ @ConfigDefault("null")
51
+ public Optional<String> getDriverPath();
31
52
 
32
- public class AthenaInputPlugin implements InputPlugin {
33
- public interface PluginTask extends Task {
34
53
  // database (required string)
35
54
  @Config("database")
36
55
  public String getDatabase();
@@ -63,12 +82,17 @@ public class AthenaInputPlugin implements InputPlugin {
63
82
  @ConfigDefault("{}")
64
83
  public ToStringMap getOptions();
65
84
 
85
+ @Config("null_to_zero")
86
+ @ConfigDefault("false")
87
+ public boolean getNullToZero();
88
+
66
89
  @ConfigInject
67
90
  BufferAllocator getBufferAllocator();
68
91
  }
69
92
 
70
93
  @Override
71
- public ConfigDiff transaction(ConfigSource config, InputPlugin.Control control) {
94
+ public ConfigDiff transaction(ConfigSource config, InputPlugin.Control control)
95
+ {
72
96
  PluginTask task = config.loadConfig(PluginTask.class);
73
97
 
74
98
  Schema schema = task.getColumns().toSchema();
@@ -78,17 +102,20 @@ public class AthenaInputPlugin implements InputPlugin {
78
102
  }
79
103
 
80
104
  @Override
81
- public ConfigDiff resume(TaskSource taskSource, Schema schema, int taskCount, InputPlugin.Control control) {
105
+ public ConfigDiff resume(TaskSource taskSource, Schema schema, int taskCount, InputPlugin.Control control)
106
+ {
82
107
  control.run(taskSource, schema, taskCount);
83
108
  return Exec.newConfigDiff();
84
109
  }
85
110
 
86
111
  @Override
87
- public void cleanup(TaskSource taskSource, Schema schema, int taskCount, List<TaskReport> successTaskReports) {
112
+ public void cleanup(TaskSource taskSource, Schema schema, int taskCount, List<TaskReport> successTaskReports)
113
+ {
88
114
  }
89
115
 
90
116
  @Override
91
- public TaskReport run(TaskSource taskSource, Schema schema, int taskIndex, PageOutput output) {
117
+ public TaskReport run(TaskSource taskSource, Schema schema, int taskIndex, PageOutput output)
118
+ {
92
119
  PluginTask task = taskSource.loadTask(PluginTask.class);
93
120
  BufferAllocator allocator = task.getBufferAllocator();
94
121
  PageBuilder pageBuilder = new PageBuilder(allocator, schema, output);
@@ -101,58 +128,93 @@ public class AthenaInputPlugin implements InputPlugin {
101
128
  connection = getAthenaConnection(task);
102
129
  statement = connection.createStatement();
103
130
  ResultSet resultSet = statement.executeQuery(task.getQuery());
131
+ boolean nullToZero = task.getNullToZero();
104
132
 
105
- ResultSetMetaData m = resultSet.getMetaData();
106
133
  while (resultSet.next()) {
107
- schema.visitColumns(new ColumnVisitor() {
134
+ schema.visitColumns(new ColumnVisitor()
135
+ {
108
136
  @Override
109
- public void timestampColumn(Column column) {
137
+ public void timestampColumn(Column column)
138
+ {
110
139
  try {
111
140
  java.sql.Timestamp t = resultSet.getTimestamp(column.getName());
112
141
  pageBuilder.setTimestamp(column, Timestamp.ofEpochMilli(t.getTime()));
113
- } catch (SQLException e) {
142
+ }
143
+ catch (SQLException e) {
114
144
  e.printStackTrace();
145
+ throw new RuntimeException(e);
115
146
  }
116
147
  }
117
148
 
118
149
  @Override
119
- public void stringColumn(Column column) {
150
+ public void stringColumn(Column column)
151
+ {
120
152
  try {
121
153
  pageBuilder.setString(column, resultSet.getString(column.getName()));
122
- } catch (SQLException e) {
154
+ }
155
+ catch (SQLException e) {
123
156
  e.printStackTrace();
157
+ throw new RuntimeException(e);
124
158
  }
125
159
  }
126
160
 
127
161
  @Override
128
- public void longColumn(Column column) {
162
+ public void longColumn(Column column)
163
+ {
129
164
  try {
130
- pageBuilder.setLong(column, resultSet.getLong(column.getName()));
131
- } catch (SQLException e) {
165
+ long ret = resultSet.getLong(column.getName());
166
+ if (resultSet.wasNull() && !nullToZero){
167
+ pageBuilder.setNull(column);
168
+ }
169
+ else {
170
+ pageBuilder.setLong(column, ret);
171
+ }
172
+ }
173
+ catch (SQLException e) {
132
174
  e.printStackTrace();
175
+ throw new RuntimeException(e);
133
176
  }
134
177
  }
135
178
 
136
179
  @Override
137
- public void doubleColumn(Column column) {
180
+ public void doubleColumn(Column column)
181
+ {
138
182
  try {
139
- pageBuilder.setDouble(column, resultSet.getDouble(column.getName()));
140
- } catch (SQLException e) {
183
+ double ret = resultSet.getDouble(column.getName());
184
+ if (resultSet.wasNull() && !nullToZero){
185
+ pageBuilder.setNull(column);
186
+ }
187
+ else {
188
+ pageBuilder.setDouble(column, ret);
189
+ }
190
+ }
191
+ catch (SQLException e) {
141
192
  e.printStackTrace();
193
+ throw new RuntimeException(e);
142
194
  }
143
195
  }
144
196
 
145
197
  @Override
146
- public void booleanColumn(Column column) {
198
+ public void booleanColumn(Column column)
199
+ {
147
200
  try {
148
- pageBuilder.setBoolean(column, resultSet.getBoolean(column.getName()));
149
- } catch (SQLException e) {
201
+ boolean ret = resultSet.getBoolean(column.getName());
202
+ if (resultSet.wasNull() && !nullToZero){
203
+ pageBuilder.setNull(column);
204
+ }
205
+ else {
206
+ pageBuilder.setBoolean(column, ret);
207
+ }
208
+ }
209
+ catch (SQLException e) {
150
210
  e.printStackTrace();
211
+ throw new RuntimeException(e);
151
212
  }
152
213
  }
153
214
 
154
215
  @Override
155
- public void jsonColumn(Column column) {
216
+ public void jsonColumn(Column column)
217
+ {
156
218
  // TODO:
157
219
  }
158
220
  });
@@ -164,19 +226,24 @@ public class AthenaInputPlugin implements InputPlugin {
164
226
  pageBuilder.close();
165
227
  resultSet.close();
166
228
  connection.close();
167
- } catch (Exception e) {
229
+ }
230
+ catch (Exception e) {
168
231
  e.printStackTrace();
169
- } finally {
232
+ throw new RuntimeException(e);
233
+ }
234
+ finally {
170
235
  try {
171
- if (statement != null)
236
+ if (statement != null) {
172
237
  statement.close();
173
- } catch (Exception ex) {
174
-
238
+ }
175
239
  }
240
+ catch (Exception ex) { }
176
241
  try {
177
- if (connection != null)
242
+ if (connection != null) {
178
243
  connection.close();
179
- } catch (Exception ex) {
244
+ }
245
+ }
246
+ catch (Exception ex) {
180
247
  ex.printStackTrace();
181
248
  }
182
249
  }
@@ -185,12 +252,14 @@ public class AthenaInputPlugin implements InputPlugin {
185
252
  }
186
253
 
187
254
  @Override
188
- public ConfigDiff guess(ConfigSource config) {
255
+ public ConfigDiff guess(ConfigSource config)
256
+ {
189
257
  return Exec.newConfigDiff();
190
258
  }
191
259
 
192
- protected Connection getAthenaConnection(PluginTask task) throws ClassNotFoundException, SQLException {
193
- Class.forName("com.amazonaws.athena.jdbc.AthenaDriver");
260
+ protected Connection getAthenaConnection(PluginTask task) throws ClassNotFoundException, SQLException
261
+ {
262
+ loadDriver("com.amazonaws.athena.jdbc.AthenaDriver", task.getDriverPath());
194
263
  Properties properties = new Properties();
195
264
  properties.put("s3_staging_dir", task.getS3StagingDir());
196
265
  properties.put("user", task.getAccessKey());
@@ -199,4 +268,84 @@ public class AthenaInputPlugin implements InputPlugin {
199
268
 
200
269
  return DriverManager.getConnection(task.getAthenaUrl(), properties);
201
270
  }
271
+
272
+ //
273
+ // copy from embulk-input-jdbc
274
+ //
275
+
276
+ protected void loadDriver(String className, Optional<String> driverPath)
277
+ {
278
+ if (driverPath.isPresent()) {
279
+ addDriverJarToClasspath(driverPath.get());
280
+ }
281
+ else {
282
+ try {
283
+ // Gradle test task will add JDBC driver to classpath
284
+ Class.forName(className);
285
+ }
286
+ catch (ClassNotFoundException ex) {
287
+ File root = findPluginRoot();
288
+ File driverLib = new File(root, "default_jdbc_driver");
289
+ File[] files = driverLib.listFiles(new FileFilter() {
290
+ @Override
291
+ public boolean accept(File file)
292
+ {
293
+ return file.isFile() && file.getName().endsWith(".jar");
294
+ }
295
+ });
296
+ if (files == null || files.length == 0) {
297
+ throw new RuntimeException("Cannot find JDBC driver in '" + root.getAbsolutePath() + "'.");
298
+ }
299
+ else {
300
+ for (File file : files) {
301
+ logger.info("JDBC Driver = " + file.getAbsolutePath());
302
+ addDriverJarToClasspath(file.getAbsolutePath());
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
+ // Load JDBC Driver
309
+ try {
310
+ Class.forName(className);
311
+ }
312
+ catch (ClassNotFoundException ex) {
313
+ throw new RuntimeException(ex);
314
+ }
315
+ }
316
+
317
+ protected void addDriverJarToClasspath(String glob)
318
+ {
319
+ // TODO match glob
320
+ PluginClassLoader loader = (PluginClassLoader) getClass().getClassLoader();
321
+ Path path = Paths.get(glob);
322
+ if (!path.toFile().exists()) {
323
+ throw new ConfigException("The specified driver jar doesn't exist: " + glob);
324
+ }
325
+ loader.addPath(Paths.get(glob));
326
+ }
327
+
328
+ protected File findPluginRoot()
329
+ {
330
+ try {
331
+ URL url = getClass().getResource("/" + getClass().getName().replace('.', '/') + ".class");
332
+ if (url.toString().startsWith("jar:")) {
333
+ url = new URL(url.toString().replaceAll("^jar:", "").replaceAll("![^!]*$", ""));
334
+ }
335
+
336
+ File folder = new File(url.toURI()).getParentFile();
337
+ for (;; folder = folder.getParentFile()) {
338
+ if (folder == null) {
339
+ throw new RuntimeException("Cannot find 'embulk-input-xxx' folder.");
340
+ }
341
+
342
+ if (folder.getName().startsWith("embulk-input-")) {
343
+ return folder;
344
+ }
345
+ }
346
+ }
347
+ catch (MalformedURLException | URISyntaxException e) {
348
+ throw new RuntimeException(e);
349
+ }
350
+ }
202
351
  }