diff --git a/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java b/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java index dd3ea21c5ef..a77392f1197 100644 --- a/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java +++ b/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java @@ -136,21 +136,9 @@ public class JarHell { /** inspect manifest for sure incompatibilities */ static void checkManifest(Manifest manifest, Path jar) { // give a nice error if jar requires a newer java version - String systemVersion = System.getProperty("java.specification.version"); String targetVersion = manifest.getMainAttributes().getValue("X-Compile-Target-JDK"); if (targetVersion != null) { - float current = Float.POSITIVE_INFINITY; - float target = Float.NEGATIVE_INFINITY; - try { - current = Float.parseFloat(systemVersion); - target = Float.parseFloat(targetVersion); - } catch (NumberFormatException e) { - // some spec changed, time for a more complex parser - } - if (current < target) { - throw new IllegalStateException(jar + " requires Java " + targetVersion - + ", your system: " + systemVersion); - } + checkJavaVersion(jar.toString(), targetVersion); } // give a nice error if jar is compiled against different es version @@ -162,6 +150,26 @@ public class JarHell { } } + /** + * Checks that the java specification version {@code targetVersion} + * required by {@code resource} is compatible with the current installation. + */ + public static void checkJavaVersion(String resource, String targetVersion) { + String systemVersion = System.getProperty("java.specification.version"); + float current = Float.POSITIVE_INFINITY; + float target = Float.NEGATIVE_INFINITY; + try { + current = Float.parseFloat(systemVersion); + target = Float.parseFloat(targetVersion); + } catch (NumberFormatException e) { + // some spec changed, time for a more complex parser + } + if (current < target) { + throw new IllegalStateException(resource + " requires Java " + targetVersion + + ", your system: " + systemVersion); + } + } + static void checkClass(Map clazzes, String clazz, Path jarpath) { Path previous = clazzes.put(clazz, jarpath); if (previous != null) { diff --git a/core/src/main/java/org/elasticsearch/plugins/PluginInfo.java b/core/src/main/java/org/elasticsearch/plugins/PluginInfo.java index 2448ede740e..66f24e3a8c8 100644 --- a/core/src/main/java/org/elasticsearch/plugins/PluginInfo.java +++ b/core/src/main/java/org/elasticsearch/plugins/PluginInfo.java @@ -19,6 +19,7 @@ package org.elasticsearch.plugins; import org.elasticsearch.Version; +import org.elasticsearch.bootstrap.JarHell; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Streamable; @@ -110,6 +111,11 @@ public class PluginInfo implements Streamable, ToXContent { if (esVersion.equals(Version.CURRENT) == false) { throw new IllegalArgumentException("Elasticsearch version [" + esVersionString + "] is too old for plugin [" + name + "]"); } + String javaVersionString = props.getProperty("java.version"); + if (javaVersionString == null) { + throw new IllegalArgumentException("Property [java.version] is missing for jvm plugin [" + name + "]"); + } + JarHell.checkJavaVersion(name, javaVersionString); isolated = Boolean.parseBoolean(props.getProperty("isolated", "true")); classname = props.getProperty("classname"); if (classname == null) { diff --git a/core/src/test/java/org/elasticsearch/plugins/PluginInfoTests.java b/core/src/test/java/org/elasticsearch/plugins/PluginInfoTests.java index 2bbc52f2033..525b3bf4a09 100644 --- a/core/src/test/java/org/elasticsearch/plugins/PluginInfoTests.java +++ b/core/src/test/java/org/elasticsearch/plugins/PluginInfoTests.java @@ -57,6 +57,7 @@ public class PluginInfoTests extends ElasticsearchTestCase { "description", "fake desc", "version", "1.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true", "classname", "FakePlugin"); PluginInfo info = PluginInfo.readFromProperties(pluginDir); @@ -119,6 +120,38 @@ public class PluginInfoTests extends ElasticsearchTestCase { } } + public void testReadFromPropertiesJavaVersionMissing() throws Exception { + Path pluginDir = createTempDir().resolve("fake-plugin"); + writeProperties(pluginDir, + "description", "fake desc", + "elasticsearch.version", Version.CURRENT.toString(), + "version", "1.0", + "jvm", "true"); + try { + PluginInfo.readFromProperties(pluginDir); + fail("expected missing java version exception"); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().contains("[java.version] is missing")); + } + } + + public void testReadFromPropertiesJavaVersionIncompatible() throws Exception { + Path pluginDir = createTempDir().resolve("fake-plugin"); + writeProperties(pluginDir, + "description", "fake desc", + "elasticsearch.version", Version.CURRENT.toString(), + "java.version", "1000000.0", + "classname", "FakePlugin", + "version", "1.0", + "jvm", "true"); + try { + PluginInfo.readFromProperties(pluginDir); + fail("expected incompatible java version exception"); + } catch (IllegalStateException e) { + assertTrue(e.getMessage(), e.getMessage().contains("fake-plugin requires Java")); + } + } + public void testReadFromPropertiesBogusElasticsearchVersion() throws Exception { Path pluginDir = createTempDir().resolve("fake-plugin"); writeProperties(pluginDir, @@ -155,6 +188,7 @@ public class PluginInfoTests extends ElasticsearchTestCase { "description", "fake desc", "version", "1.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true"); try { PluginInfo.readFromProperties(pluginDir); @@ -170,7 +204,6 @@ public class PluginInfoTests extends ElasticsearchTestCase { writeProperties(pluginDir, "description", "fake desc", "version", "1.0", - "elasticsearch.version", Version.CURRENT.toString(), "site", "true"); PluginInfo info = PluginInfo.readFromProperties(pluginDir); assertTrue(info.isSite()); @@ -183,7 +216,6 @@ public class PluginInfoTests extends ElasticsearchTestCase { writeProperties(pluginDir, "description", "fake desc", "version", "1.0", - "elasticsearch.version", Version.CURRENT.toString(), "site", "true"); try { PluginInfo.readFromProperties(pluginDir); diff --git a/core/src/test/java/org/elasticsearch/plugins/PluginManagerTests.java b/core/src/test/java/org/elasticsearch/plugins/PluginManagerTests.java index aaaf68cf953..042e209a444 100644 --- a/core/src/test/java/org/elasticsearch/plugins/PluginManagerTests.java +++ b/core/src/test/java/org/elasticsearch/plugins/PluginManagerTests.java @@ -131,6 +131,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest { "description", "fake desc", "version", "1.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true", "classname", "FakePlugin"); @@ -175,6 +176,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest { "description", "fake desc", "version", "1.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true", "classname", "FakePlugin"); @@ -210,6 +212,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest { "description", "fake desc", "version", "2.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true", "classname", "FakePlugin"); @@ -245,6 +248,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest { "description", "fake desc", "version", "3.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true", "classname", "FakePlugin"); @@ -272,6 +276,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest { "description", "fake desc", "version", "1.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true", "classname", "FakePlugin"); @@ -305,6 +310,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest { "description", "fake desc", "version", "1.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true", "classname", "FakePlugin"); assertStatusOk(String.format(Locale.ROOT, "install %s --url %s --verbose", pluginName, pluginUrl)); @@ -412,6 +418,7 @@ public class PluginManagerTests extends ElasticsearchIntegrationTest { "description", "fake desc", "version", "1.0.0", "elasticsearch.version", Version.CURRENT.toString(), + "java.version", System.getProperty("java.specification.version"), "jvm", "true", "classname", "FakePlugin"); diff --git a/dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties b/dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties index b9e7eac1302..82b74bdf1b2 100644 --- a/dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties +++ b/dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties @@ -1,15 +1,24 @@ -# elasticsearch plugin descriptor file +# Elasticsearch plugin descriptor file +# This file must be at the root of the plugin. +# A plugin can be 'jvm', 'site', or both # -# example: +# example jvm plugin: # jvm=true # classname=foo.bar.BazPlugin -# isolated=true -# site=false # description=My cool plugin # version=2.0 # elasticsearch.version=2.0 +# java.version=1.7 # -# A plugin can be 'jvm', 'site', or both +# example site plugin: +# site=true +# description=My cool plugin +# version=1.0 +# +# 'description': simple summary of the plugin +description=${project.description} +# 'version': plugin's version +version=${project.version} # # 'jvm': true if the 'classname' class should be loaded # from jar files in the root directory of the plugin @@ -20,13 +29,11 @@ classname=${elasticsearch.plugin.classname} # passing false is deprecated, and only intended to support plugins # that have hard dependencies against each other isolated=${elasticsearch.plugin.isolated} +# 'java.version' version of java the code is built against +java.version=${maven.compiler.target} +# 'elasticsearch.version' version of elasticsearch compiled against +elasticsearch.version=${elasticsearch.version} # # 'site': true if the contents of _site should be served site=${elasticsearch.plugin.site} # -# 'description': simple summary of the plugin -description=${project.description} -# 'version': plugin's version -version=${project.version} -# 'elasticsearch.version' version of elasticsearch compiled against -elasticsearch.version=${elasticsearch.version}