Browse Source

Merge pull request #12424 from rmuir/plugin_java_version

make java.version mandatory for jvm plugins
Robert Muir 10 years ago
parent
commit
219f48119c

+ 21 - 13
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<String,Path> clazzes, String clazz, Path jarpath) {
         Path previous = clazzes.put(clazz, jarpath);
         if (previous != null) {

+ 6 - 0
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) {

+ 34 - 2
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);

+ 7 - 0
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");
         

+ 55 - 17
dev-tools/src/main/resources/plugin-metadata/plugin-descriptor.properties

@@ -1,32 +1,70 @@
-# elasticsearch plugin descriptor file
+# Elasticsearch plugin descriptor file
+# This file must exist as 'plugin-descriptor.properties' at
+# the root directory of all plugins.
+#
+# A plugin can be 'site', 'jvm', or both.
+#
+### example site plugin for "foo":
+#
+# foo.zip <-- zip file for the plugin, with this structure:
+#   _site/ <-- the contents that will be served
+#   plugin-descriptor.properties <-- example contents below:
+#
+# site=true
+# description=My cool plugin
+# version=1.0
+#
+### example jvm plugin for "foo"
+#
+# foo.zip <-- zip file for the plugin, with this structure:
+#   <arbitrary name1>.jar <-- classes, resources, dependencies
+#   <arbitrary nameN>.jar <-- any number of jars
+#   plugin-descriptor.properties <-- example contents below:
 #
-# example:
 # 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
+#
+### mandatory elements for all plugins:
+#
+# 'description': simple summary of the plugin
+description=${project.description}
+#
+# 'version': plugin's version
+version=${project.version}
+#
+### mandatory elements for site plugins:
+#
+# 'site': set to true to indicate contents of the _site/
+#  directory in the root of the plugin should be served.
+site=${elasticsearch.plugin.site}
 #
-# A plugin can be 'jvm', 'site', or both
+### mandatory elements for jvm plugins :
 #
 # 'jvm': true if the 'classname' class should be loaded
-#  from jar files in the root directory of the plugin
+#  from jar files in the root directory of the plugin.
+#  Note that only jar files in the root directory are
+#  added to the classpath for the plugin! If you need
+#  other resources, package them into a resources jar.
 jvm=${elasticsearch.plugin.jvm}
-# 'classname': the name of the class to load. 
+#
+# 'classname': the name of the class to load, fully-qualified.
 classname=${elasticsearch.plugin.classname}
-# 'isolated': true if the plugin should have its own classloader.
-# passing false is deprecated, and only intended to support plugins 
-# that have hard dependencies against each other
-isolated=${elasticsearch.plugin.isolated}
 #
-# 'site': true if the contents of _site should be served
-site=${elasticsearch.plugin.site}
+# 'java.version' version of java the code is built against
+java.version=${maven.compiler.target}
 #
-# '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}
+#
+### deprecated elements for jvm plugins :
+#
+# 'isolated': true if the plugin should have its own classloader.
+# passing false is deprecated, and only intended to support plugins 
+# that have hard dependencies against each other. If this is
+# not specified, then the plugin is isolated by default.
+isolated=${elasticsearch.plugin.isolated}
+#