embulk 0.8.25-java → 0.8.26-java
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.
- checksums.yaml +4 -4
- data/build.gradle +16 -1
- data/embulk-cli/src/main/java/org/embulk/cli/EmbulkMigrate.java +6 -3
- data/embulk-core/build.gradle +7 -0
- data/embulk-core/src/main/java/org/embulk/EmbulkService.java +2 -0
- data/embulk-core/src/main/java/org/embulk/plugin/InjectedPluginSource.java +1 -1
- data/embulk-core/src/main/java/org/embulk/plugin/MavenPluginType.java +21 -6
- data/embulk-core/src/main/java/org/embulk/plugin/PluginClassLoader.java +42 -2
- data/embulk-core/src/main/java/org/embulk/plugin/PluginSourceNotMatchException.java +6 -0
- data/embulk-core/src/main/java/org/embulk/plugin/PluginType.java +2 -1
- data/embulk-core/src/main/java/org/embulk/plugin/jar/InvalidJarPluginException.java +14 -0
- data/embulk-core/src/main/java/org/embulk/plugin/jar/JarPluginLoader.java +205 -0
- data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenArtifactFinder.java +134 -0
- data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenArtifactNotFoundException.java +20 -0
- data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenPluginSource.java +187 -0
- data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenPluginSourceModule.java +22 -0
- data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenRepositoryNotFoundException.java +31 -0
- data/embulk-core/src/main/resources/embulk/parent_first_packages.properties +3 -1
- data/embulk-core/src/main/resources/embulk/parent_first_resources.properties +2 -1
- data/embulk-core/src/test/java/org/embulk/EmbulkTestRuntime.java +8 -0
- data/embulk-core/src/test/java/org/embulk/plugin/TestPluginType.java +24 -0
- data/embulk-core/src/test/java/org/embulk/plugin/TestPluginTypeSerDe.java +17 -0
- data/embulk-core/src/test/java/org/embulk/plugin/jar/ExampleJarSpiV0.java +9 -0
- data/embulk-core/src/test/java/org/embulk/plugin/jar/JarBuilder.java +101 -0
- data/embulk-core/src/test/java/org/embulk/plugin/jar/TestJarPluginLoader.java +60 -0
- data/embulk-core/src/test/java/org/embulk/plugin/maven/TestMavenArtifactFinder.java +41 -0
- data/embulk-core/src/test/resources/m2.test/.gitignore +1 -0
- data/embulk-core/src/test/resources/m2.test/org/embulk/example/embulk-example-maven-artifact/0.1.2/embulk-example-maven-artifact-0.1.2.jar +0 -0
- data/embulk-core/src/test/resources/m2.test/org/embulk/example/embulk-example-maven-artifact/0.1.2/embulk-example-maven-artifact-0.1.2.jar.sha1 +1 -0
- data/embulk-core/src/test/resources/m2.test/org/embulk/example/embulk-example-maven-artifact/0.1.2/embulk-example-maven-artifact-0.1.2.pom +9 -0
- data/embulk-core/src/test/resources/m2.test/org/embulk/example/embulk-example-maven-artifact/0.1.2/embulk-example-maven-artifact-0.1.2.pom.sha1 +1 -0
- data/embulk-docs/src/built-in.rst +26 -9
- data/embulk-docs/src/release.rst +1 -0
- data/embulk-docs/src/release/release-0.8.26.rst +16 -0
- data/embulk-standards/src/main/java/org/embulk/standards/ConfigInputPlugin.java +170 -0
- data/embulk-standards/src/main/java/org/embulk/standards/StandardPluginModule.java +1 -0
- data/lib/embulk/version.rb +1 -1
- metadata +58 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67e9c5003f422b52f56fd7347f77dda2ea07d86e
|
4
|
+
data.tar.gz: ac13f8e09bcc9998ba716fc96e6e98e0546605ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a275c7189877da26bed04a116dab321b0bf5d9c8f378143aa743c2fa05ae0806fb8d27eabaad76c6bdd7b06971a1b8f5ea2aa8a52152aa7e67a129545e417bc
|
7
|
+
data.tar.gz: 6ce56d2cfec57fc2db846f7be7aaf5209e30ac5180b28f0d9930f7cebd333f614e443dcb1e57b49bc58683e4b1a595239809bbe50d4915f9bd21e5d59597abb7
|
data/build.gradle
CHANGED
@@ -16,7 +16,7 @@ def release_projects = [project(":embulk-core"), project(":embulk-standards"), p
|
|
16
16
|
|
17
17
|
allprojects {
|
18
18
|
group = 'org.embulk'
|
19
|
-
version = '0.8.
|
19
|
+
version = '0.8.26'
|
20
20
|
|
21
21
|
ext {
|
22
22
|
jrubyVersion = '9.1.5.0'
|
@@ -100,6 +100,9 @@ subprojects {
|
|
100
100
|
tasks.withType(JavaCompile) {
|
101
101
|
options.compilerArgs << "-Xlint:unchecked" //<< "-Xlint:deprecation"
|
102
102
|
}
|
103
|
+
tasks.withType(Test) {
|
104
|
+
systemProperties System.properties.findAll { it.key.startsWith("org.embulk") }
|
105
|
+
}
|
103
106
|
tasks.withType(FindBugs) {
|
104
107
|
reports {
|
105
108
|
xml.enabled = false
|
@@ -227,6 +230,18 @@ project(':embulk-cli') {
|
|
227
230
|
apply plugin: 'com.github.johnrengelman.shadow'
|
228
231
|
|
229
232
|
shadowJar {
|
233
|
+
// 'org.apache.maven' is used in:
|
234
|
+
// - embulk-cli: EmbulkMigrate and EmbulkSelfUpdate (from v0.8.17)
|
235
|
+
// - embulk-core: MavenPluginSource and the related (from v0.8.26)
|
236
|
+
relocate 'org.apache.maven', 'org.embulk.third_party.org.apache.maven'
|
237
|
+
|
238
|
+
// 'org.codehaus.plexus' is used from 'org.apache.maven'.
|
239
|
+
relocate 'org.codehaus.plexus', 'org.embulk.third_party.org.codehaus.plexus'
|
240
|
+
|
241
|
+
// 'org.eclipse.aether' is used in:
|
242
|
+
// - embulk-core: MavenPluginSource and the related (from v0.8.26)
|
243
|
+
relocate 'org.eclipse.aether', 'org.embulk.third_party.org.eclipse.aether'
|
244
|
+
|
230
245
|
// NOTE: This 'Implementation-Version' in the manifest is referred to provide the Embulk version at runtime.
|
231
246
|
// See also: embulk-core/src/main/java/org/embulk/EmbulkVersion.java
|
232
247
|
manifest {
|
@@ -10,6 +10,7 @@ import java.nio.file.Path;
|
|
10
10
|
import java.nio.file.PathMatcher;
|
11
11
|
import java.nio.file.Paths;
|
12
12
|
import java.nio.file.SimpleFileVisitor;
|
13
|
+
import java.nio.file.StandardCopyOption;
|
13
14
|
import java.nio.file.StandardOpenOption;
|
14
15
|
import java.nio.file.attribute.BasicFileAttributes;
|
15
16
|
import java.util.ArrayList;
|
@@ -76,7 +77,7 @@ public class EmbulkMigrate
|
|
76
77
|
System.out.println("Done. No files are modified.");
|
77
78
|
}
|
78
79
|
else {
|
79
|
-
System.out.println("Done. Please check
|
80
|
+
System.out.println("Done. Please check modified files.");
|
80
81
|
}
|
81
82
|
}
|
82
83
|
|
@@ -236,7 +237,9 @@ public class EmbulkMigrate
|
|
236
237
|
{
|
237
238
|
Path destinationPath = this.basePath.resolve(destinationFileName);
|
238
239
|
Files.createDirectories(destinationPath.getParent());
|
239
|
-
Files.copy(EmbulkMigrate.class.getClassLoader().getResourceAsStream(sourceResourcePath), destinationPath
|
240
|
+
Files.copy(EmbulkMigrate.class.getClassLoader().getResourceAsStream(sourceResourcePath), destinationPath,
|
241
|
+
StandardCopyOption.REPLACE_EXISTING);
|
242
|
+
this.modifiedFiles.add(destinationPath);
|
240
243
|
}
|
241
244
|
|
242
245
|
public boolean match(String filePath, Pattern pattern)
|
@@ -424,7 +427,7 @@ public class EmbulkMigrate
|
|
424
427
|
private static final Pattern OLD_EMBULK_IN_GEMSPEC = Pattern.compile(
|
425
428
|
"embulk-");
|
426
429
|
private static final Pattern GRADLE_VERSION_IN_WRAPPER = Pattern.compile(
|
427
|
-
"gradle-[23]\\.\\d+(\\.\\d+)
|
430
|
+
"gradle-[23]\\.\\d+(\\.\\d+)?-");
|
428
431
|
private static final Pattern JSON_COLUMN_METHOD_IN_ALL_JAVA = Pattern.compile(
|
429
432
|
"void\\s+jsonColumn");
|
430
433
|
private static final Pattern TIMESTAMP_COLUMN_METHOD_IN_ALL_JAVA = Pattern.compile(
|
data/embulk-core/build.gradle
CHANGED
@@ -43,6 +43,13 @@ dependencies {
|
|
43
43
|
// For embulk/guess/charset.rb. See also embulk.gemspec
|
44
44
|
compile 'com.ibm.icu:icu4j:54.1.1'
|
45
45
|
|
46
|
+
// For MavenPluginSource / MavenArtifactFinder.
|
47
|
+
compile 'org.eclipse.aether:aether-api:1.1.0'
|
48
|
+
compile 'org.eclipse.aether:aether-spi:1.1.0'
|
49
|
+
compile 'org.eclipse.aether:aether-util:1.1.0'
|
50
|
+
compile 'org.eclipse.aether:aether-impl:1.1.0'
|
51
|
+
compile 'org.apache.maven:maven-aether-provider:3.3.9'
|
52
|
+
|
46
53
|
gems 'rubygems:bundler:1.10.6'
|
47
54
|
gems 'rubygems:msgpack:1.1.0'
|
48
55
|
gems 'rubygems:liquid:3.0.6'
|
@@ -11,6 +11,7 @@ import org.embulk.exec.ExecModule;
|
|
11
11
|
import org.embulk.exec.ExtensionServiceLoaderModule;
|
12
12
|
import org.embulk.plugin.PluginClassLoaderModule;
|
13
13
|
import org.embulk.plugin.BuiltinPluginSourceModule;
|
14
|
+
import org.embulk.plugin.maven.MavenPluginSourceModule;
|
14
15
|
import org.embulk.jruby.JRubyScriptingModule;
|
15
16
|
import static com.google.common.base.Preconditions.checkState;
|
16
17
|
|
@@ -45,6 +46,7 @@ public class EmbulkService
|
|
45
46
|
new ExtensionServiceLoaderModule(systemConfig),
|
46
47
|
new PluginClassLoaderModule(systemConfig),
|
47
48
|
new BuiltinPluginSourceModule(),
|
49
|
+
new MavenPluginSourceModule(systemConfig),
|
48
50
|
new JRubyScriptingModule(systemConfig));
|
49
51
|
}
|
50
52
|
|
@@ -10,10 +10,11 @@ import java.util.Objects;
|
|
10
10
|
public final class MavenPluginType
|
11
11
|
extends PluginType
|
12
12
|
{
|
13
|
-
private MavenPluginType(final String name, final String group, final String version)
|
13
|
+
private MavenPluginType(final String name, final String group, final String classifier, final String version)
|
14
14
|
{
|
15
15
|
super("maven", name);
|
16
16
|
this.group = group;
|
17
|
+
this.classifier = classifier;
|
17
18
|
this.version = version;
|
18
19
|
|
19
20
|
final StringBuilder fullNameBuilder = new StringBuilder();
|
@@ -23,6 +24,10 @@ public final class MavenPluginType
|
|
23
24
|
fullNameBuilder.append(name);
|
24
25
|
fullNameBuilder.append(":");
|
25
26
|
fullNameBuilder.append(version);
|
27
|
+
if (classifier != null) {
|
28
|
+
fullNameBuilder.append(":");
|
29
|
+
fullNameBuilder.append(classifier);
|
30
|
+
}
|
26
31
|
this.fullName = fullNameBuilder.toString();
|
27
32
|
|
28
33
|
final HashMap<String, String> fullMapMutable = new HashMap<String, String>();
|
@@ -33,12 +38,13 @@ public final class MavenPluginType
|
|
33
38
|
this.fullMap = Collections.unmodifiableMap(fullMapMutable);
|
34
39
|
}
|
35
40
|
|
36
|
-
public static MavenPluginType create(
|
41
|
+
public static MavenPluginType create(
|
42
|
+
final String name, final String group, final String classifier, final String version)
|
37
43
|
{
|
38
|
-
if (name == null) {
|
39
|
-
throw new NullPointerException("\"name\" must
|
44
|
+
if (name == null || group == null || version == null) {
|
45
|
+
throw new NullPointerException("\"name\", \"group\" and \"version\" must be present.");
|
40
46
|
}
|
41
|
-
return new MavenPluginType(name, group, version);
|
47
|
+
return new MavenPluginType(name, group, classifier, version);
|
42
48
|
}
|
43
49
|
|
44
50
|
@JsonValue
|
@@ -53,6 +59,12 @@ public final class MavenPluginType
|
|
53
59
|
return this.group;
|
54
60
|
}
|
55
61
|
|
62
|
+
@JsonProperty("classifier")
|
63
|
+
public final String getClassifier()
|
64
|
+
{
|
65
|
+
return this.classifier;
|
66
|
+
}
|
67
|
+
|
56
68
|
@JsonProperty("version")
|
57
69
|
public final String getVersion()
|
58
70
|
{
|
@@ -67,7 +79,7 @@ public final class MavenPluginType
|
|
67
79
|
@Override
|
68
80
|
public final int hashCode()
|
69
81
|
{
|
70
|
-
return Objects.hash(getSourceType(), getName(), this.group, this.version);
|
82
|
+
return Objects.hash(getSourceType(), getName(), this.group, this.classifier, this.version);
|
71
83
|
}
|
72
84
|
|
73
85
|
@Override
|
@@ -80,6 +92,8 @@ public final class MavenPluginType
|
|
80
92
|
return (this.getSourceType().equals(other.getSourceType()) &&
|
81
93
|
this.getName().equals(other.getName()) &&
|
82
94
|
this.getGroup().equals(other.getGroup()) &&
|
95
|
+
((this.getClassifier() == null && other.getClassifier() == null) ||
|
96
|
+
(this.getClassifier() != null && this.getClassifier().equals(other.getClassifier()))) &&
|
83
97
|
this.getVersion().equals(other.getVersion()));
|
84
98
|
}
|
85
99
|
|
@@ -91,6 +105,7 @@ public final class MavenPluginType
|
|
91
105
|
}
|
92
106
|
|
93
107
|
private final String group;
|
108
|
+
private final String classifier; // |classifier| can be null.
|
94
109
|
private final String version;
|
95
110
|
private final String fullName;
|
96
111
|
private final Map<String, String> fullMap;
|
@@ -42,6 +42,15 @@ public class PluginClassLoader
|
|
42
42
|
}));
|
43
43
|
}
|
44
44
|
|
45
|
+
/**
|
46
|
+
* Adds the specified path to the list of URLs (for {@code URLClassLoader}) to search for classes and resources.
|
47
|
+
*
|
48
|
+
* It internally calls {@code URLClassLoader#addURL}.
|
49
|
+
*
|
50
|
+
* Some plugins (embulk-input-jdbc, for example) are calling this method to load external JAR files.
|
51
|
+
*
|
52
|
+
* @see https://github.com/embulk/embulk-input-jdbc/blob/ebfff0b249d507fc730c87e08b56e6aa492060ca/embulk-input-jdbc/src/main/java/org/embulk/input/jdbc/AbstractJdbcInputPlugin.java#L586-L595
|
53
|
+
*/
|
45
54
|
public void addPath(Path path)
|
46
55
|
{
|
47
56
|
try {
|
@@ -56,17 +65,45 @@ public class PluginClassLoader
|
|
56
65
|
super.addURL(url);
|
57
66
|
}
|
58
67
|
|
68
|
+
/**
|
69
|
+
* Loads the class with the specified binary name prioritized by the "parent-first" condition.
|
70
|
+
*
|
71
|
+
* It copy-cats {@code ClassLoader#loadClass} while the "parent-first" priorities are considered.
|
72
|
+
*
|
73
|
+
* If the specified class is "parent-first", it behaves the same as {@code ClassLoader#loadClass} ordered as below.
|
74
|
+
*
|
75
|
+
* <ol>
|
76
|
+
*
|
77
|
+
* <li><p>Invoke the {@code #findLoadedClass} method to check if the class has already been loaded.</p></li>
|
78
|
+
*
|
79
|
+
* <li><p>Invoke the parent's {@code #loadClass} method.
|
80
|
+
*
|
81
|
+
* <li><p>Invoke the {@code #findClass} method of this class loader to find the class.</p></li>
|
82
|
+
*
|
83
|
+
* </ol>
|
84
|
+
*
|
85
|
+
* If the specified class is "NOT parent-first", the 2nd and 3rd actions are swapped.
|
86
|
+
*
|
87
|
+
* @see https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#loadClass(java.lang.String,%20boolean)
|
88
|
+
* @see http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/jdk7u141-b02/src/share/classes/java/lang/ClassLoader.java
|
89
|
+
*/
|
59
90
|
@Override
|
60
91
|
protected Class<?> loadClass(String name, boolean resolve)
|
61
92
|
throws ClassNotFoundException
|
62
93
|
{
|
63
94
|
synchronized (getClassLoadingLock(name)) {
|
64
|
-
|
95
|
+
// If the class has already been loaded by this {@code ClassLoader} or the parent's {@code ClassLoader},
|
96
|
+
// find the loaded class and return it.
|
97
|
+
final Class<?> loadedClass = findLoadedClass(name);
|
98
|
+
|
65
99
|
if (loadedClass != null) {
|
66
100
|
return resolveClass(loadedClass, resolve);
|
67
101
|
}
|
68
102
|
|
69
|
-
boolean parentFirst = isParentFirstPackage(name);
|
103
|
+
final boolean parentFirst = isParentFirstPackage(name);
|
104
|
+
|
105
|
+
// If the class is "not parent-first" (not to be loaded by the parent at first),
|
106
|
+
// try {@code #findClass} of the child's ({@code PluginClassLoader}'s).
|
70
107
|
if (!parentFirst) {
|
71
108
|
try {
|
72
109
|
return resolveClass(findClass(name), resolve);
|
@@ -74,11 +111,14 @@ public class PluginClassLoader
|
|
74
111
|
}
|
75
112
|
}
|
76
113
|
|
114
|
+
// If the class is "parent-first" (to be loaded by the parent at first), try this part at first.
|
115
|
+
// If the class is "not parent-first" (not to be loaded by the parent at first), the above part runs first.
|
77
116
|
try {
|
78
117
|
return resolveClass(getParent().loadClass(name), resolve);
|
79
118
|
} catch (ClassNotFoundException ignored) {
|
80
119
|
}
|
81
120
|
|
121
|
+
// If the class is "parent-first" (to be loaded by the parent at first), this part runs after the above.
|
82
122
|
if (parentFirst) {
|
83
123
|
return resolveClass(findClass(name), resolve);
|
84
124
|
}
|
@@ -5,6 +5,7 @@ public class PluginSourceNotMatchException
|
|
5
5
|
{
|
6
6
|
public PluginSourceNotMatchException()
|
7
7
|
{
|
8
|
+
super();
|
8
9
|
}
|
9
10
|
|
10
11
|
public PluginSourceNotMatchException(String message)
|
@@ -16,4 +17,9 @@ public class PluginSourceNotMatchException
|
|
16
17
|
{
|
17
18
|
super(cause);
|
18
19
|
}
|
20
|
+
|
21
|
+
public PluginSourceNotMatchException(String message, Throwable cause)
|
22
|
+
{
|
23
|
+
super(message, cause);
|
24
|
+
}
|
19
25
|
}
|
@@ -79,8 +79,9 @@ public abstract class PluginType
|
|
79
79
|
{
|
80
80
|
final String name = stringMap.get("name");
|
81
81
|
final String group = stringMap.get("group");
|
82
|
+
final String classifier = stringMap.get("classifier");
|
82
83
|
final String version = stringMap.get("version");
|
83
|
-
return MavenPluginType.create(name, group, version);
|
84
|
+
return MavenPluginType.create(name, group, classifier, version);
|
84
85
|
}
|
85
86
|
default:
|
86
87
|
throw new IllegalArgumentException("\"source\" must be one of: [\"default\", \"maven\"]");
|
@@ -0,0 +1,14 @@
|
|
1
|
+
package org.embulk.plugin.jar;
|
2
|
+
|
3
|
+
public class InvalidJarPluginException
|
4
|
+
extends Exception {
|
5
|
+
public InvalidJarPluginException(final String message)
|
6
|
+
{
|
7
|
+
super(message);
|
8
|
+
}
|
9
|
+
|
10
|
+
public InvalidJarPluginException(final String message, final Throwable cause)
|
11
|
+
{
|
12
|
+
super(message, cause);
|
13
|
+
}
|
14
|
+
}
|
@@ -0,0 +1,205 @@
|
|
1
|
+
package org.embulk.plugin.jar;
|
2
|
+
|
3
|
+
import com.google.common.collect.ImmutableList;
|
4
|
+
import java.io.IOError;
|
5
|
+
import java.io.IOException;
|
6
|
+
import java.net.JarURLConnection;
|
7
|
+
import java.net.MalformedURLException;
|
8
|
+
import java.net.URI;
|
9
|
+
import java.net.URL;
|
10
|
+
import java.nio.file.Path;
|
11
|
+
import java.util.jar.Attributes;
|
12
|
+
import java.util.jar.Manifest;
|
13
|
+
import org.embulk.plugin.PluginClassLoader;
|
14
|
+
import org.embulk.plugin.PluginClassLoaderFactory;
|
15
|
+
|
16
|
+
/**
|
17
|
+
* JarPluginLoader loads a JAR-based Embulk plugin class.
|
18
|
+
*
|
19
|
+
* It implements {@code AutoCloseable} so that it can load the contents lazily in the future.
|
20
|
+
* It is recommended to try-with-resources to use this class.
|
21
|
+
*/
|
22
|
+
public class JarPluginLoader
|
23
|
+
implements AutoCloseable
|
24
|
+
{
|
25
|
+
public static final String MANIFEST_PLUGIN_MAIN_CLASS = "Embulk-Plugin-Main-Class";
|
26
|
+
public static final String MANIFEST_PLUGIN_SPI_VERSION = "Embulk-Plugin-Spi-Version";
|
27
|
+
|
28
|
+
private JarPluginLoader(final Manifest pluginManifest,
|
29
|
+
final Attributes pluginManifestAttributes,
|
30
|
+
final Class pluginMainClass)
|
31
|
+
{
|
32
|
+
this.pluginManifest = pluginManifest;
|
33
|
+
this.pluginManifestAttributes = pluginManifestAttributes;
|
34
|
+
this.pluginMainClass = pluginMainClass;
|
35
|
+
}
|
36
|
+
|
37
|
+
public static JarPluginLoader load(final Path jarPath, final PluginClassLoaderFactory classLoaderFactory)
|
38
|
+
throws InvalidJarPluginException
|
39
|
+
{
|
40
|
+
final JarURLConnection connection = openJarURLConnection(jarPath);
|
41
|
+
final Manifest manifest = loadJarPluginManifest(connection, jarPath);
|
42
|
+
final Attributes manifestAttributes = manifest.getMainAttributes();
|
43
|
+
final int spiVersion = getPluginSpiVersionFromManifest(manifestAttributes);
|
44
|
+
|
45
|
+
if (spiVersion == 0) {
|
46
|
+
final String mainClassName = getPluginMainClassNameFromManifest(manifestAttributes);
|
47
|
+
final Class mainClass = loadJarPluginMainClass(jarPath, mainClassName, classLoaderFactory);
|
48
|
+
return new JarPluginLoader(manifest, manifestAttributes, mainClass);
|
49
|
+
}
|
50
|
+
|
51
|
+
throw new InvalidJarPluginException("Unknown SPI version of JAR plugin: " + spiVersion);
|
52
|
+
}
|
53
|
+
|
54
|
+
public Class getPluginMainClass()
|
55
|
+
throws InvalidJarPluginException
|
56
|
+
{
|
57
|
+
return this.pluginMainClass;
|
58
|
+
}
|
59
|
+
|
60
|
+
public int getPluginSpiVersion()
|
61
|
+
throws InvalidJarPluginException
|
62
|
+
{
|
63
|
+
return getPluginSpiVersionFromManifest(this.pluginManifestAttributes);
|
64
|
+
}
|
65
|
+
|
66
|
+
@Override
|
67
|
+
public void close()
|
68
|
+
throws InvalidJarPluginException
|
69
|
+
{
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Opens JarURLConnection for the given JAR file path.
|
74
|
+
*
|
75
|
+
* Note that JarURLConnection does not have {@code disconnect} nor {@code close}.
|
76
|
+
*/
|
77
|
+
private static JarURLConnection openJarURLConnection(final Path jarPath)
|
78
|
+
throws InvalidJarPluginException
|
79
|
+
{
|
80
|
+
// jar:file:/...
|
81
|
+
final URL jarUrl;
|
82
|
+
try {
|
83
|
+
jarUrl = new URL("jar:" + jarPath.toUri().toURL().toString() + "!/");
|
84
|
+
}
|
85
|
+
catch (MalformedURLException ex) {
|
86
|
+
throw new InvalidJarPluginException("JAR plugin path specified is invalid: " + jarPath.toString(), ex);
|
87
|
+
}
|
88
|
+
|
89
|
+
try {
|
90
|
+
return (JarURLConnection) jarUrl.openConnection();
|
91
|
+
}
|
92
|
+
catch (IOException ex) {
|
93
|
+
throw new InvalidJarPluginException("JAR plugin specified is formatted wrongly: " + jarPath.toString(), ex);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
private static Manifest loadJarPluginManifest(final JarURLConnection connection, final Path jarPath)
|
98
|
+
throws InvalidJarPluginException
|
99
|
+
{
|
100
|
+
try {
|
101
|
+
return connection.getManifest();
|
102
|
+
}
|
103
|
+
catch (IOException ex) {
|
104
|
+
throw new InvalidJarPluginException("Manifest in JAR plugin specified is invalid: " + jarPath.toString(),
|
105
|
+
ex);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
private static Class loadJarPluginMainClass(final Path jarPath,
|
110
|
+
final String pluginMainClassName,
|
111
|
+
final PluginClassLoaderFactory pluginClassLoaderFactory)
|
112
|
+
throws InvalidJarPluginException
|
113
|
+
{
|
114
|
+
final URI fileUriJar;
|
115
|
+
try {
|
116
|
+
fileUriJar = jarPath.toUri();
|
117
|
+
}
|
118
|
+
catch (IOError ex) {
|
119
|
+
throw new InvalidJarPluginException("[FATAL] JAR plugin path specified is invalid: " + jarPath.toString(),
|
120
|
+
ex);
|
121
|
+
}
|
122
|
+
catch (SecurityException ex) {
|
123
|
+
throw new InvalidJarPluginException("Security manager prohibits getting the working directory: " +
|
124
|
+
jarPath.toString() +
|
125
|
+
". Specifying an absolute path for JAR plugin may solve this.",
|
126
|
+
ex);
|
127
|
+
}
|
128
|
+
|
129
|
+
// file:/...
|
130
|
+
final URL fileUrlJar;
|
131
|
+
try {
|
132
|
+
fileUrlJar = fileUriJar.toURL();
|
133
|
+
}
|
134
|
+
catch (IllegalArgumentException ex) {
|
135
|
+
throw new InvalidJarPluginException("[FATAL/INTERNAL] JAR plugin path as URI is not absolute.", ex);
|
136
|
+
}
|
137
|
+
catch (MalformedURLException ex) {
|
138
|
+
throw new InvalidJarPluginException("JAR plugin path specified is invalid: " + jarPath.toString(), ex);
|
139
|
+
}
|
140
|
+
|
141
|
+
|
142
|
+
final PluginClassLoader pluginClassLoader =
|
143
|
+
pluginClassLoaderFactory.create(ImmutableList.of(fileUrlJar), JarPluginLoader.class.getClassLoader());
|
144
|
+
|
145
|
+
final Class pluginMainClass;
|
146
|
+
try {
|
147
|
+
pluginMainClass = pluginClassLoader.loadClass(pluginMainClassName);
|
148
|
+
}
|
149
|
+
catch (ClassNotFoundException ex) {
|
150
|
+
throw new InvalidJarPluginException("Class " + pluginMainClassName + " not found in " + jarPath.toString(),
|
151
|
+
ex);
|
152
|
+
}
|
153
|
+
|
154
|
+
return pluginMainClass;
|
155
|
+
}
|
156
|
+
|
157
|
+
private static int getPluginSpiVersionFromManifest(final Attributes manifestAttributes)
|
158
|
+
throws InvalidJarPluginException
|
159
|
+
{
|
160
|
+
final String spiVersionString = getAttributeFromManifest(manifestAttributes, MANIFEST_PLUGIN_SPI_VERSION);
|
161
|
+
|
162
|
+
if (spiVersionString == null) {
|
163
|
+
throw new InvalidJarPluginException("SPI version of JAR plugin is not specified.");
|
164
|
+
}
|
165
|
+
|
166
|
+
try {
|
167
|
+
return Integer.parseInt(spiVersionString);
|
168
|
+
}
|
169
|
+
catch (NumberFormatException ex) {
|
170
|
+
throw new InvalidJarPluginException("SPI version of JAR plugin is not an integer: \"" +
|
171
|
+
spiVersionString +
|
172
|
+
"\"", ex);
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
private static String getPluginMainClassNameFromManifest(final Attributes manifestAttributes)
|
177
|
+
throws InvalidJarPluginException
|
178
|
+
{
|
179
|
+
final String pluginMainClassName = getAttributeFromManifest(manifestAttributes, MANIFEST_PLUGIN_MAIN_CLASS);
|
180
|
+
|
181
|
+
if (pluginMainClassName == null) {
|
182
|
+
throw new InvalidJarPluginException("Main class name of JAR plugin is not specified.");
|
183
|
+
}
|
184
|
+
|
185
|
+
return pluginMainClassName;
|
186
|
+
}
|
187
|
+
|
188
|
+
private static String getAttributeFromManifest(final Attributes manifestAttributes, final String attributeName)
|
189
|
+
throws InvalidJarPluginException
|
190
|
+
{
|
191
|
+
try {
|
192
|
+
return manifestAttributes.getValue(attributeName);
|
193
|
+
}
|
194
|
+
catch (IllegalArgumentException ex) {
|
195
|
+
throw new InvalidJarPluginException("[FATAL/INTERNAL] " +
|
196
|
+
attributeName +
|
197
|
+
" is considered invalid as a manifest attribute.",
|
198
|
+
ex);
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
private final Manifest pluginManifest;
|
203
|
+
private final Attributes pluginManifestAttributes;
|
204
|
+
private final Class pluginMainClass;
|
205
|
+
}
|