diff --git a/src/main/java/org/elasticsearch/plugins/PluginsService.java b/src/main/java/org/elasticsearch/plugins/PluginsService.java index 9a7e3c2ce57..a4e6d735410 100644 --- a/src/main/java/org/elasticsearch/plugins/PluginsService.java +++ b/src/main/java/org/elasticsearch/plugins/PluginsService.java @@ -21,7 +21,6 @@ package org.elasticsearch.plugins; import com.google.common.base.Charsets; import com.google.common.collect.*; -import com.google.common.primitives.Chars; import org.apache.lucene.util.Constants; import org.apache.lucene.util.IOUtils; import org.elasticsearch.ElasticsearchException; @@ -42,13 +41,13 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.env.Environment; -import java.io.*; +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Method; import java.net.URL; -import java.nio.charset.Charset; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; +import java.nio.file.*; import java.util.*; import static org.elasticsearch.common.io.FileSystemUtils.isAccessibleDirectory; @@ -61,6 +60,9 @@ public class PluginsService extends AbstractComponent { public static final String ES_PLUGIN_PROPERTIES = "es-plugin.properties"; public static final String LOAD_PLUGIN_FROM_CLASSPATH = "load_classpath_plugins"; + private static final PathMatcher PLUGIN_LIB_MATCHER = FileSystems.getDefault().getPathMatcher("glob:**.{jar,zip}"); + + private final Environment environment; /** @@ -368,6 +370,7 @@ public class PluginsService extends AbstractComponent { return; } try (DirectoryStream stream = Files.newDirectoryStream(pluginsDirectory)) { + for (Path plugin : stream) { // We check that subdirs are directories and readable if (!isAccessibleDirectory(plugin, logger)) { @@ -389,7 +392,7 @@ public class PluginsService extends AbstractComponent { // if there are jars in it, add it as well for (Path libFile : libFiles) { - if (!(libFile.getFileName().endsWith(".jar") || libFile.getFileName().endsWith(".zip"))) { + if (!hasLibExtension(libFile)) { continue; } addURL.invoke(classLoader, libFile.toUri().toURL()); @@ -401,6 +404,10 @@ public class PluginsService extends AbstractComponent { } } + protected static boolean hasLibExtension(Path lib) { + return PLUGIN_LIB_MATCHER.matches(lib); + } + private Path[] files(Path from) throws IOException { try (DirectoryStream stream = Files.newDirectoryStream(from)) { return Iterators.toArray(stream.iterator(), Path.class); diff --git a/src/test/java/org/elasticsearch/plugins/PluginServiceTests.java b/src/test/java/org/elasticsearch/plugins/PluginServiceTests.java new file mode 100644 index 00000000000..50328f93d43 --- /dev/null +++ b/src/test/java/org/elasticsearch/plugins/PluginServiceTests.java @@ -0,0 +1,120 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.plugins; + +import com.google.common.collect.ImmutableList; +import org.elasticsearch.action.admin.cluster.node.info.PluginInfo; +import org.elasticsearch.common.collect.Tuple; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.nodesinfo.SimpleNodesInfoTests; +import org.elasticsearch.plugins.loading.classpath.InClassPathPlugin; +import org.elasticsearch.test.ElasticsearchIntegrationTest; +import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; +import org.junit.Test; + +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.instanceOf; + +@ClusterScope(scope= ElasticsearchIntegrationTest.Scope.TEST, numDataNodes=0, numClientNodes = 1, transportClientRatio = 0) +public class PluginServiceTests extends ElasticsearchIntegrationTest { + + @Test + public void testPluginLoadingFromClassName() throws URISyntaxException { + Settings settings = settingsBuilder() + // Defines a plugin in classpath + .put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, true) + .put("plugins." + PluginsService.ES_PLUGIN_PROPERTIES_FILE_KEY, "es-plugin-test.properties") + // Defines a plugin in settings + .put("plugin.types", InSettingsPlugin.class.getName()) + .build(); + + SimpleNodesInfoTests.startNodeWithPlugins(settings, "/org/elasticsearch/plugins/loading/"); + + Plugin plugin = getPlugin("in-settings-plugin"); + assertNotNull("InSettingsPlugin (defined below in this class) must be loaded", plugin); + assertThat(plugin, instanceOf(InSettingsPlugin.class)); + + plugin = getPlugin("in-classpath-plugin"); + assertNotNull("InClassPathPlugin (defined in package ) must be loaded", plugin); + assertThat(plugin, instanceOf(InClassPathPlugin.class)); + + plugin = getPlugin("in-jar-plugin"); + assertNotNull("InJarPlugin (packaged as a JAR file in a plugins directory) must be loaded", plugin); + assertThat(plugin.getClass().getName(), endsWith("InJarPlugin")); + + plugin = getPlugin("in-zip-plugin"); + assertNotNull("InZipPlugin (packaged as a Zipped file in a plugins directory) must be loaded", plugin); + assertThat(plugin.getClass().getName(), endsWith("InZipPlugin")); + } + + @Test + public void testHasLibExtension() { + Path p = Paths.get("path", "to", "plugin.jar"); + assertTrue(PluginsService.hasLibExtension(p)); + + p = Paths.get("path", "to", "plugin.zip"); + assertTrue(PluginsService.hasLibExtension(p)); + + p = Paths.get("path", "to", "plugin.tar.gz"); + assertFalse(PluginsService.hasLibExtension(p)); + + p = Paths.get("path", "to", "plugin"); + assertFalse(PluginsService.hasLibExtension(p)); + } + + private Plugin getPlugin(String pluginName) { + assertNotNull("cannot check plugin existence with a null plugin's name", pluginName); + PluginsService pluginsService = internalCluster().getInstance(PluginsService.class); + ImmutableList> plugins = pluginsService.plugins(); + + if ((plugins != null) && (!plugins.isEmpty())) { + for (Tuple plugin:plugins) { + if (pluginName.equals(plugin.v1().getName())) { + return plugin.v2(); + } + } + } + return null; + } + + static class InSettingsPlugin extends AbstractPlugin { + + private final Settings settings; + + public InSettingsPlugin(Settings settings) { + this.settings = settings; + } + + @Override + public String name() { + return "in-settings-plugin"; + } + + @Override + public String description() { + return "A plugin defined in settings"; + } + } +} diff --git a/src/test/java/org/elasticsearch/plugins/loading/classpath/InClassPathPlugin.java b/src/test/java/org/elasticsearch/plugins/loading/classpath/InClassPathPlugin.java new file mode 100644 index 00000000000..cf4959e62d1 --- /dev/null +++ b/src/test/java/org/elasticsearch/plugins/loading/classpath/InClassPathPlugin.java @@ -0,0 +1,35 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.plugins.loading.classpath; + +import org.elasticsearch.plugins.AbstractPlugin; + +public class InClassPathPlugin extends AbstractPlugin { + + @Override + public String name() { + return "in-classpath-plugin"; + } + + @Override + public String description() { + return "A plugin defined in class path"; + } +} diff --git a/src/test/java/org/elasticsearch/plugins/loading/classpath/es-plugin-test.properties b/src/test/java/org/elasticsearch/plugins/loading/classpath/es-plugin-test.properties new file mode 100644 index 00000000000..f57bea58cf2 --- /dev/null +++ b/src/test/java/org/elasticsearch/plugins/loading/classpath/es-plugin-test.properties @@ -0,0 +1,19 @@ +################################################################ +# Licensed to Elasticsearch under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch licenses this file to you under +# the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +################################################################ +plugin=org.elasticsearch.plugins.loading.classpath.InClassPathPlugin \ No newline at end of file diff --git a/src/test/resources/org/elasticsearch/plugins/loading/jar/in-jar-plugin.jar b/src/test/resources/org/elasticsearch/plugins/loading/jar/in-jar-plugin.jar new file mode 100644 index 00000000000..6b854823f14 Binary files /dev/null and b/src/test/resources/org/elasticsearch/plugins/loading/jar/in-jar-plugin.jar differ diff --git a/src/test/resources/org/elasticsearch/plugins/loading/zip/in-zip-plugin.jar b/src/test/resources/org/elasticsearch/plugins/loading/zip/in-zip-plugin.jar new file mode 100644 index 00000000000..6b35430f34d Binary files /dev/null and b/src/test/resources/org/elasticsearch/plugins/loading/zip/in-zip-plugin.jar differ