parent
a9c8624c67
commit
960d353dbd
|
@ -40,7 +40,6 @@ plugins per node:
|
|||
* `site`: `true` if the plugin is a site plugin
|
||||
* `jvm`: `true` if the plugin is a plugin running in the JVM
|
||||
* `url`: URL if the plugin is a site plugin
|
||||
* `isolation`: whether the plugin is loaded in isolation (`true`) or not (`false`)
|
||||
|
||||
The result will look similar to:
|
||||
|
||||
|
|
|
@ -142,20 +142,6 @@ bin/plugin --install mobz/elasticsearch-head --timeout 1m
|
|||
bin/plugin --install mobz/elasticsearch-head --timeout 0
|
||||
-----------------------------------
|
||||
|
||||
added[1.1.0]
|
||||
[float]
|
||||
==== Plugins isolation
|
||||
|
||||
Since Elasticsearch 1.1, by default, each plugin is loaded in _isolation_ (in its dedicated `ClassLoader`) to avoid class clashes between the various plugins and their associated libraries. The default can be changed through the `plugins.isolation` property in `elasticsearch.yml`, by setting it to `false`:
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
plugins.isolation: false
|
||||
--------------------------------------------------
|
||||
|
||||
Do note that each plugin can specify its _mandatory_ isolation through the `isolation` property in its `es-plugin.properties` configuration. In this (rare) case, the plugin setting is used, overwriting whatever default used by Elasticsearch.
|
||||
|
||||
|
||||
[float]
|
||||
[[known-plugins]]
|
||||
=== Known Plugins
|
||||
|
|
|
@ -41,7 +41,6 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
static final XContentBuilderString JVM = new XContentBuilderString("jvm");
|
||||
static final XContentBuilderString SITE = new XContentBuilderString("site");
|
||||
static final XContentBuilderString VERSION = new XContentBuilderString("version");
|
||||
static final XContentBuilderString ISOLATION = new XContentBuilderString("isolation");
|
||||
}
|
||||
|
||||
private String name;
|
||||
|
@ -49,7 +48,6 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
private boolean site;
|
||||
private boolean jvm;
|
||||
private String version;
|
||||
private boolean isolation;
|
||||
|
||||
public PluginInfo() {
|
||||
}
|
||||
|
@ -62,9 +60,8 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
* @param site true if it's a site plugin
|
||||
* @param jvm true if it's a jvm plugin
|
||||
* @param version Version number is applicable (NA otherwise)
|
||||
* @param isolation true if it's an isolated plugin
|
||||
*/
|
||||
public PluginInfo(String name, String description, boolean site, boolean jvm, String version, boolean isolation) {
|
||||
public PluginInfo(String name, String description, boolean site, boolean jvm, String version) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.site = site;
|
||||
|
@ -74,7 +71,6 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
} else {
|
||||
this.version = VERSION_NOT_AVAILABLE;
|
||||
}
|
||||
this.isolation = isolation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,13 +121,6 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Plugin isolation
|
||||
*/
|
||||
public boolean isIsolation() {
|
||||
return isolation;
|
||||
}
|
||||
|
||||
public static PluginInfo readPluginInfo(StreamInput in) throws IOException {
|
||||
PluginInfo info = new PluginInfo();
|
||||
info.readFrom(in);
|
||||
|
@ -149,11 +138,6 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
} else {
|
||||
this.version = VERSION_NOT_AVAILABLE;
|
||||
}
|
||||
if (in.getVersion().onOrAfter(Version.V_1_1_0)) {
|
||||
this.isolation = in.readBoolean();
|
||||
} else {
|
||||
this.isolation = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -165,9 +149,6 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
if (out.getVersion().onOrAfter(Version.V_1_0_0_RC2)) {
|
||||
out.writeString(version);
|
||||
}
|
||||
if (out.getVersion().onOrAfter(Version.V_1_1_0)) {
|
||||
out.writeBoolean(isolation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -181,7 +162,6 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
}
|
||||
builder.field(Fields.JVM, jvm);
|
||||
builder.field(Fields.SITE, site);
|
||||
builder.field(Fields.ISOLATION, isolation);
|
||||
builder.endObject();
|
||||
|
||||
return builder;
|
||||
|
@ -207,13 +187,12 @@ public class PluginInfo implements Streamable, Serializable, ToXContent {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("PluginInfo{");
|
||||
final StringBuffer sb = new StringBuffer("PluginInfo{");
|
||||
sb.append("name='").append(name).append('\'');
|
||||
sb.append(", description='").append(description).append('\'');
|
||||
sb.append(", site=").append(site);
|
||||
sb.append(", jvm=").append(jvm);
|
||||
sb.append(", version='").append(version).append('\'');
|
||||
sb.append(", isolation=").append(isolation);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* 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.Lists;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
|
||||
public class PluginClassLoader extends URLClassLoader {
|
||||
|
||||
private final ClassLoader system;
|
||||
private final URL url;
|
||||
|
||||
PluginClassLoader(URL[] urls, ClassLoader parent) throws IOException {
|
||||
super(urls, parent);
|
||||
url = (urls != null && urls.length > 0 ? urls[0] : null);
|
||||
|
||||
ClassLoader sys = getSystemClassLoader();
|
||||
while (sys.getParent() != null) {
|
||||
sys = sys.getParent();
|
||||
}
|
||||
|
||||
system = sys;
|
||||
}
|
||||
|
||||
// load first from system class loader then fall back to this one
|
||||
@Override
|
||||
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
Class<?> c = findLoadedClass(name);
|
||||
if (c == null) {
|
||||
// check system class loader (jvm & bootclasspath)
|
||||
if (system != null) {
|
||||
try {
|
||||
c = system.loadClass(name);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
if (c == null) {
|
||||
try {
|
||||
// check plugin classloader
|
||||
c = findClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// fall back to parent
|
||||
c = super.loadClass(name, resolve);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resolve) {
|
||||
resolveClass(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(String name) {
|
||||
// apply same rules frmo loadClass
|
||||
URL url = null;
|
||||
if (system != null) {
|
||||
url = system.getResource(name);
|
||||
}
|
||||
if (url == null) {
|
||||
url = findResource(name);
|
||||
if (url == null) {
|
||||
url = super.getResource(name);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
List<URL> urls = Lists.newArrayList();
|
||||
if (system != null) {
|
||||
urls.addAll(Collections.list(system.getResources(name)));
|
||||
}
|
||||
urls.addAll(Collections.list(findResources(name)));
|
||||
|
||||
ClassLoader parent = getParent();
|
||||
if (parent != null) {
|
||||
urls.addAll(Collections.list(parent.getResources(name)));
|
||||
}
|
||||
|
||||
return Collections.enumeration(urls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(Locale.US, "PluginClassLoader for url [%s], classpath [%s], systemCL [%s]", url, Arrays.toString(getURLs()), system);
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* 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.Lists;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Booleans;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public final class PluginUtils {
|
||||
|
||||
private PluginUtils() {}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Plugin loadPlugin(String className, Settings settings, ClassLoader classLoader) {
|
||||
try {
|
||||
Class<? extends Plugin> pluginClass = (Class<? extends Plugin>) classLoader.loadClass(className);
|
||||
try {
|
||||
return pluginClass.getConstructor(Settings.class).newInstance(settings);
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
return pluginClass.newInstance();
|
||||
} catch (Exception e1) {
|
||||
throw new ElasticsearchException("No constructor for [" + pluginClass + "]. A plugin class must " +
|
||||
"have either an empty default constructor or a single argument constructor accepting a " +
|
||||
"Settings instance");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("Failed to load plugin class [" + className + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
static List<File> pluginClassPathAsFiles(File pluginFolder) throws IOException {
|
||||
List<File> cpFiles = Lists.newArrayList();
|
||||
cpFiles.add(pluginFolder);
|
||||
|
||||
List<File> libFiles = Lists.newArrayList();
|
||||
File[] files = pluginFolder.listFiles();
|
||||
if (files != null) {
|
||||
Collections.addAll(libFiles, files);
|
||||
}
|
||||
File libLocation = new File(pluginFolder, "lib");
|
||||
if (libLocation.exists() && libLocation.isDirectory()) {
|
||||
files = libLocation.listFiles();
|
||||
if (files != null) {
|
||||
Collections.addAll(libFiles, files);
|
||||
}
|
||||
}
|
||||
|
||||
// if there are jars in it, add it as well
|
||||
for (File libFile : libFiles) {
|
||||
if (libFile.getName().endsWith(".jar") || libFile.getName().endsWith(".zip")) {
|
||||
cpFiles.add(libFile);
|
||||
}
|
||||
}
|
||||
|
||||
return cpFiles;
|
||||
}
|
||||
|
||||
static boolean lookupIsolation(List<URL> pluginProperties, boolean defaultIsolation) throws IOException {
|
||||
Properties props = new Properties();
|
||||
InputStream is = null;
|
||||
for (URL prop : pluginProperties) {
|
||||
try {
|
||||
props.load(prop.openStream());
|
||||
return Booleans.parseBoolean(props.getProperty("isolation"), defaultIsolation);
|
||||
} finally {
|
||||
IOUtils.closeWhileHandlingException(is);
|
||||
}
|
||||
}
|
||||
return defaultIsolation;
|
||||
}
|
||||
|
||||
static List<URL> lookupPluginProperties(List<File> pluginClassPath) throws Exception {
|
||||
if (pluginClassPath.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<URL> found = Lists.newArrayList();
|
||||
|
||||
for (File file : pluginClassPath) {
|
||||
String toString = file.getName();
|
||||
if (toString.endsWith(".jar") || toString.endsWith(".zip")) {
|
||||
JarFile jar = new JarFile(file);
|
||||
try {
|
||||
JarEntry jarEntry = jar.getJarEntry("es-plugin.properties");
|
||||
if (jarEntry != null) {
|
||||
found.add(new URL("jar:" + file.toURI().toString() + "!/es-plugin.properties"));
|
||||
}
|
||||
} finally {
|
||||
IOUtils.closeWhileHandlingException(jar);
|
||||
}
|
||||
}
|
||||
else {
|
||||
File props = new File(file, "es-plugin.properties");
|
||||
if (props.exists() && props.canRead()) {
|
||||
found.add(props.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static URL[] convertFileToUrl(List<File> pluginClassPath) throws IOException {
|
||||
URL[] urls = new URL[pluginClassPath.size()];
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
urls[i] = pluginClassPath.get(i).toURI().toURL();
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ import org.elasticsearch.index.CloseableIndexComponent;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
|
@ -88,8 +89,8 @@ public class PluginsService extends AbstractComponent {
|
|||
// first we load all the default plugins from the settings
|
||||
String[] defaultPluginsClasses = settings.getAsArray("plugin.types");
|
||||
for (String pluginClass : defaultPluginsClasses) {
|
||||
Plugin plugin = PluginUtils.loadPlugin(pluginClass, settings, settings.getClassLoader());
|
||||
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), hasSite(plugin.name()), true, PluginInfo.VERSION_NOT_AVAILABLE, false);
|
||||
Plugin plugin = loadPlugin(pluginClass, settings);
|
||||
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), hasSite(plugin.name()), true, PluginInfo.VERSION_NOT_AVAILABLE);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("plugin loaded from settings [{}]", pluginInfo);
|
||||
}
|
||||
|
@ -97,7 +98,8 @@ public class PluginsService extends AbstractComponent {
|
|||
}
|
||||
|
||||
// now, find all the ones that are in the classpath
|
||||
tupleBuilder.addAll(loadPlugins());
|
||||
loadPluginsIntoClassLoader();
|
||||
tupleBuilder.addAll(loadPluginsFromClasspath(settings));
|
||||
this.plugins = tupleBuilder.build();
|
||||
|
||||
// We need to build a List of jvm and site plugins for checking mandatory plugins
|
||||
|
@ -315,110 +317,103 @@ public class PluginsService extends AbstractComponent {
|
|||
return cachedPluginsInfo;
|
||||
}
|
||||
|
||||
private List<Tuple<PluginInfo,Plugin>> loadPlugins() {
|
||||
File pluginsFile = environment.pluginsFile();
|
||||
if (!isAccessibleDirectory(pluginsFile, logger)) {
|
||||
return Collections.emptyList();
|
||||
private void loadPluginsIntoClassLoader() {
|
||||
File pluginsDirectory = environment.pluginsFile();
|
||||
if (!isAccessibleDirectory(pluginsDirectory, logger)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Tuple<PluginInfo, Plugin>> pluginData = Lists.newArrayList();
|
||||
|
||||
boolean defaultIsolation = settings.getAsBoolean("plugins.isolation", Boolean.FALSE);
|
||||
ClassLoader esClassLoader = settings.getClassLoader();
|
||||
ClassLoader classLoader = settings.getClassLoader();
|
||||
Class classLoaderClass = classLoader.getClass();
|
||||
Method addURL = null;
|
||||
boolean discoveredAddUrl = false;
|
||||
|
||||
File[] pluginsFiles = pluginsFile.listFiles();
|
||||
|
||||
if (pluginsFiles != null) {
|
||||
for (File pluginRoot : pluginsFiles) {
|
||||
if (isAccessibleDirectory(pluginRoot, logger)) {
|
||||
try {
|
||||
logger.trace("--- adding plugin [" + pluginRoot.getAbsolutePath() + "]");
|
||||
// check isolation
|
||||
List<File> pluginClassPath = PluginUtils.pluginClassPathAsFiles(pluginRoot);
|
||||
List<URL> pluginProperties = PluginUtils.lookupPluginProperties(pluginClassPath);
|
||||
boolean isolated = PluginUtils.lookupIsolation(pluginProperties, defaultIsolation);
|
||||
|
||||
if (isolated) {
|
||||
logger.trace("--- creating isolated space for plugin [" + pluginRoot.getAbsolutePath() + "]");
|
||||
PluginClassLoader pcl = new PluginClassLoader(PluginUtils.convertFileToUrl(pluginClassPath), esClassLoader);
|
||||
pluginData.addAll(loadPlugin(pluginClassPath, pluginProperties, pcl, true));
|
||||
} else {
|
||||
if (!discoveredAddUrl) {
|
||||
discoveredAddUrl = true;
|
||||
Class<?> esClassLoaderClass = esClassLoader.getClass();
|
||||
|
||||
while (!esClassLoaderClass.equals(Object.class)) {
|
||||
try {
|
||||
addURL = esClassLoaderClass.getDeclaredMethod("addURL", URL.class);
|
||||
addURL.setAccessible(true);
|
||||
break;
|
||||
} catch (NoSuchMethodException e) {
|
||||
// no method, try the parent
|
||||
esClassLoaderClass = esClassLoaderClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addURL == null) {
|
||||
logger.debug("failed to find addURL method on classLoader [" + esClassLoader + "] to add methods");
|
||||
}
|
||||
else {
|
||||
for (File file : pluginClassPath) {
|
||||
addURL.invoke(esClassLoader, file.toURI().toURL());
|
||||
}
|
||||
pluginData.addAll(loadPlugin(pluginClassPath, pluginProperties, esClassLoader, false));
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.warn("failed to add plugin [" + pluginRoot.getAbsolutePath() + "]", e);
|
||||
}
|
||||
}
|
||||
while (!classLoaderClass.equals(Object.class)) {
|
||||
try {
|
||||
addURL = classLoaderClass.getDeclaredMethod("addURL", URL.class);
|
||||
addURL.setAccessible(true);
|
||||
break;
|
||||
} catch (NoSuchMethodException e) {
|
||||
// no method, try the parent
|
||||
classLoaderClass = classLoaderClass.getSuperclass();
|
||||
}
|
||||
} else {
|
||||
logger.debug("failed to list plugins from {}. Check your right access.", pluginsFile.getAbsolutePath());
|
||||
}
|
||||
if (addURL == null) {
|
||||
logger.debug("failed to find addURL method on classLoader [" + classLoader + "] to add methods");
|
||||
return;
|
||||
}
|
||||
|
||||
return pluginData;
|
||||
for (File plugin : pluginsDirectory.listFiles()) {
|
||||
// We check that subdirs are directories and readable
|
||||
if (!isAccessibleDirectory(plugin, logger)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.trace("--- adding plugin [{}]", plugin.getAbsolutePath());
|
||||
|
||||
try {
|
||||
// add the root
|
||||
addURL.invoke(classLoader, plugin.toURI().toURL());
|
||||
// gather files to add
|
||||
List<File> libFiles = Lists.newArrayList();
|
||||
if (plugin.listFiles() != null) {
|
||||
libFiles.addAll(Arrays.asList(plugin.listFiles()));
|
||||
}
|
||||
File libLocation = new File(plugin, "lib");
|
||||
if (libLocation.exists() && libLocation.isDirectory() && libLocation.listFiles() != null) {
|
||||
libFiles.addAll(Arrays.asList(libLocation.listFiles()));
|
||||
}
|
||||
|
||||
// if there are jars in it, add it as well
|
||||
for (File libFile : libFiles) {
|
||||
if (!(libFile.getName().endsWith(".jar") || libFile.getName().endsWith(".zip"))) {
|
||||
continue;
|
||||
}
|
||||
addURL.invoke(classLoader, libFile.toURI().toURL());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.warn("failed to add plugin [" + plugin + "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<? extends Tuple<PluginInfo, Plugin>> loadPlugin(List<File> pluginClassPath, List<URL> properties, ClassLoader classLoader, boolean isolation) throws Exception {
|
||||
List<Tuple<PluginInfo, Plugin>> plugins = Lists.newArrayList();
|
||||
private ImmutableList<Tuple<PluginInfo,Plugin>> loadPluginsFromClasspath(Settings settings) {
|
||||
ImmutableList.Builder<Tuple<PluginInfo, Plugin>> plugins = ImmutableList.builder();
|
||||
|
||||
Enumeration<URL> entries = Collections.enumeration(properties);
|
||||
while (entries.hasMoreElements()) {
|
||||
URL pluginUrl = entries.nextElement();
|
||||
Properties pluginProps = new Properties();
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = pluginUrl.openStream();
|
||||
pluginProps.load(is);
|
||||
String pluginClassName = pluginProps.getProperty("plugin");
|
||||
if (pluginClassName == null) {
|
||||
throw new IllegalArgumentException("No plugin class specified");
|
||||
// Trying JVM plugins: looking for es-plugin.properties files
|
||||
try {
|
||||
Enumeration<URL> pluginUrls = settings.getClassLoader().getResources(ES_PLUGIN_PROPERTIES);
|
||||
while (pluginUrls.hasMoreElements()) {
|
||||
URL pluginUrl = pluginUrls.nextElement();
|
||||
Properties pluginProps = new Properties();
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = pluginUrl.openStream();
|
||||
pluginProps.load(is);
|
||||
String pluginClassName = pluginProps.getProperty("plugin");
|
||||
String pluginVersion = pluginProps.getProperty("version", PluginInfo.VERSION_NOT_AVAILABLE);
|
||||
Plugin plugin = loadPlugin(pluginClassName, settings);
|
||||
|
||||
// Is it a site plugin as well? Does it have also an embedded _site structure
|
||||
File siteFile = new File(new File(environment.pluginsFile(), plugin.name()), "_site");
|
||||
boolean isSite = isAccessibleDirectory(siteFile, logger);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("found a jvm plugin [{}], [{}]{}",
|
||||
plugin.name(), plugin.description(), isSite ? ": with _site structure" : "");
|
||||
}
|
||||
|
||||
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), isSite, true, pluginVersion);
|
||||
|
||||
plugins.add(new Tuple<>(pluginInfo, plugin));
|
||||
} catch (Throwable e) {
|
||||
logger.warn("failed to load plugin from [" + pluginUrl + "]", e);
|
||||
} finally {
|
||||
IOUtils.closeWhileHandlingException(is);
|
||||
}
|
||||
String pluginVersion = pluginProps.getProperty("version", PluginInfo.VERSION_NOT_AVAILABLE);
|
||||
Plugin plugin = PluginUtils.loadPlugin(pluginClassName, settings, classLoader);
|
||||
|
||||
// Is it a site plugin as well? Does it have also an embedded _site structure
|
||||
File siteFile = new File(new File(environment.pluginsFile(), plugin.name()), "_site");
|
||||
boolean isSite = isAccessibleDirectory(siteFile, logger);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("found a jvm plugin [{}], [{}]{}",
|
||||
plugin.name(), plugin.description(), isSite ? ": with _site structure" : "");
|
||||
}
|
||||
|
||||
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), isSite, true, pluginVersion, isolation);
|
||||
plugins.add(new Tuple<>(pluginInfo, plugin));
|
||||
} catch (Throwable e) {
|
||||
logger.warn("failed to load plugin from [" + pluginUrl + "]", e);
|
||||
} finally {
|
||||
IOUtils.closeWhileHandlingException(is);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warn("failed to find jvm plugins from classpath", e);
|
||||
}
|
||||
|
||||
return plugins;
|
||||
return plugins.build();
|
||||
}
|
||||
|
||||
private ImmutableList<Tuple<PluginInfo,Plugin>> loadSitePlugins() {
|
||||
|
@ -471,7 +466,7 @@ public class PluginsService extends AbstractComponent {
|
|||
logger.trace("found a site plugin name [{}], version [{}], description [{}]",
|
||||
name, version, description);
|
||||
}
|
||||
sitePlugins.add(new Tuple<PluginInfo, Plugin>(new PluginInfo(name, description, true, false, version, false), null));
|
||||
sitePlugins.add(new Tuple<PluginInfo, Plugin>(new PluginInfo(name, description, true, false, version), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -494,4 +489,27 @@ public class PluginsService extends AbstractComponent {
|
|||
File sitePluginDir = new File(pluginsFile, name + "/_site");
|
||||
return isAccessibleDirectory(sitePluginDir, logger);
|
||||
}
|
||||
}
|
||||
|
||||
private Plugin loadPlugin(String className, Settings settings) {
|
||||
try {
|
||||
Class<? extends Plugin> pluginClass = (Class<? extends Plugin>) settings.getClassLoader().loadClass(className);
|
||||
Plugin plugin;
|
||||
try {
|
||||
plugin = pluginClass.getConstructor(Settings.class).newInstance(settings);
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
plugin = pluginClass.getConstructor().newInstance();
|
||||
} catch (NoSuchMethodException e1) {
|
||||
throw new ElasticsearchException("No constructor for [" + pluginClass + "]. A plugin class must " +
|
||||
"have either an empty default constructor or a single argument constructor accepting a " +
|
||||
"Settings instance");
|
||||
}
|
||||
}
|
||||
|
||||
return plugin;
|
||||
|
||||
} catch (Throwable e) {
|
||||
throw new ElasticsearchException("Failed to load plugin class [" + className + "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,6 @@ public class RestPluginsAction extends AbstractCatAction {
|
|||
table.addCell("component", "alias:c;desc:component");
|
||||
table.addCell("version", "alias:v;desc:component version");
|
||||
table.addCell("type", "alias:t;desc:type (j for JVM, s for Site)");
|
||||
table.addCell("isolation", "alias:i;desc:isolation");
|
||||
table.addCell("url", "alias:u;desc:url for site plugins");
|
||||
table.addCell("description", "alias:d;default:false;desc:plugin details");
|
||||
table.endHeaders();
|
||||
|
@ -118,7 +117,6 @@ public class RestPluginsAction extends AbstractCatAction {
|
|||
}
|
||||
}
|
||||
table.addCell(type);
|
||||
table.addCell(pluginInfo.isIsolation() ? "x" : "");
|
||||
table.addCell(pluginInfo.getUrl());
|
||||
table.addCell(pluginInfo.getDescription());
|
||||
table.endRow();
|
||||
|
|
|
@ -132,43 +132,37 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
|
|||
logger.info("--> full json answer, status " + response.toString());
|
||||
|
||||
assertNodeContainsPlugins(response, server1NodeId,
|
||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST,// No JVM Plugin
|
||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No Site Plugin
|
||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, // No JVM Plugin
|
||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No Site Plugin
|
||||
|
||||
assertNodeContainsPlugins(response, server2NodeId,
|
||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, // No JVM Plugin
|
||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, // No JVM Plugin
|
||||
Lists.newArrayList(Fields.SITE_PLUGIN), // Site Plugin
|
||||
Lists.newArrayList(Fields.SITE_PLUGIN_DESCRIPTION),
|
||||
Lists.newArrayList(Fields.SITE_PLUGIN_VERSION),
|
||||
Lists.newArrayList(Boolean.FALSE));
|
||||
Lists.newArrayList(Fields.SITE_PLUGIN_VERSION));
|
||||
|
||||
assertNodeContainsPlugins(response, server3NodeId,
|
||||
Lists.newArrayList(TestPlugin.Fields.NAME), // JVM Plugin
|
||||
Lists.newArrayList(TestPlugin.Fields.DESCRIPTION),
|
||||
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE),
|
||||
Lists.newArrayList(Boolean.FALSE),
|
||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No site Plugin
|
||||
Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);// No site Plugin
|
||||
|
||||
assertNodeContainsPlugins(response, server4NodeId,
|
||||
Lists.newArrayList(TestNoVersionPlugin.Fields.NAME), // JVM Plugin
|
||||
Lists.newArrayList(TestNoVersionPlugin.Fields.DESCRIPTION),
|
||||
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE),
|
||||
Lists.newArrayList(Boolean.FALSE),
|
||||
Lists.newArrayList(Fields.SITE_PLUGIN, TestNoVersionPlugin.Fields.NAME),// Site Plugin
|
||||
Lists.newArrayList(PluginInfo.DESCRIPTION_NOT_AVAILABLE),
|
||||
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE),
|
||||
Lists.newArrayList(Boolean.FALSE));
|
||||
Lists.newArrayList(PluginInfo.VERSION_NOT_AVAILABLE));
|
||||
}
|
||||
|
||||
private void assertNodeContainsPlugins(NodesInfoResponse response, String nodeId,
|
||||
List<String> expectedJvmPluginNames,
|
||||
List<String> expectedJvmPluginDescriptions,
|
||||
List<String> expectedJvmVersions,
|
||||
List<Boolean> expectedJvmIsolations,
|
||||
List<String> expectedSitePluginNames,
|
||||
List<String> expectedSitePluginDescriptions,
|
||||
List<String> expectedSiteVersions,
|
||||
List<Boolean> expectedSiteIsolations) {
|
||||
List<String> expectedSiteVersions) {
|
||||
|
||||
assertThat(response.getNodesMap().get(nodeId), notNullValue());
|
||||
|
||||
|
@ -190,11 +184,6 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
|
|||
assertThat(jvmPluginVersions, hasItem(pluginVersion));
|
||||
}
|
||||
|
||||
List<Boolean> jvmPluginIsolations = FluentIterable.from(plugins.getInfos()).filter(jvmPluginPredicate).transform(isolationFunction).toList();
|
||||
for (Boolean pluginIsolation : expectedJvmIsolations) {
|
||||
assertThat(jvmPluginIsolations, hasItem(pluginIsolation));
|
||||
}
|
||||
|
||||
FluentIterable<String> jvmUrls = FluentIterable.from(plugins.getInfos())
|
||||
.filter(and(jvmPluginPredicate, Predicates.not(sitePluginPredicate)))
|
||||
.filter(isNull())
|
||||
|
@ -219,11 +208,6 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
|
|||
for (String pluginVersion : expectedSiteVersions) {
|
||||
assertThat(sitePluginVersions, hasItem(pluginVersion));
|
||||
}
|
||||
|
||||
List<Boolean> sitePluginIsolations = FluentIterable.from(plugins.getInfos()).filter(sitePluginPredicate).transform(isolationFunction).toList();
|
||||
for (Boolean pluginIsolation : expectedSiteIsolations) {
|
||||
assertThat(sitePluginIsolations, hasItem(pluginIsolation));
|
||||
}
|
||||
}
|
||||
|
||||
private String startNodeWithPlugins(int nodeId, String ... pluginClassNames) throws URISyntaxException {
|
||||
|
@ -283,10 +267,4 @@ public class SimpleNodesInfoTests extends ElasticsearchIntegrationTest {
|
|||
return pluginInfo.getVersion();
|
||||
}
|
||||
};
|
||||
|
||||
private Function<PluginInfo, Boolean> isolationFunction = new Function<PluginInfo, Boolean>() {
|
||||
public Boolean apply(PluginInfo pluginInfo) {
|
||||
return pluginInfo.isIsolation();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* 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.io.Files;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.FileSystemUtils;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
|
||||
// NB: the tests uses System Properties to pass the information from different plugins (loaded in separate CLs) to the test.
|
||||
// hence the use of try/finally blocks to clean these up after the test has been executed as otherwise the test framework will trigger a failure
|
||||
@ClusterScope(scope = ElasticsearchIntegrationTest.Scope.TEST, numNodes = 0)
|
||||
public class IsolatedPluginTests extends ElasticsearchIntegrationTest {
|
||||
|
||||
private static final Settings SETTINGS;
|
||||
private static final File PLUGIN_DIR;
|
||||
private Properties props;
|
||||
|
||||
static {
|
||||
PLUGIN_DIR = Files.createTempDir();
|
||||
|
||||
SETTINGS = ImmutableSettings.settingsBuilder()
|
||||
.put("discovery.zen.ping.multicast.enabled", false)
|
||||
.put("force.http.enabled", true)
|
||||
.put("plugins.isolation", true)
|
||||
.put("path.plugins", PLUGIN_DIR.getAbsolutePath())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
props = new Properties();
|
||||
props.putAll(System.getProperties());
|
||||
|
||||
logger.info("Installing plugins into folder {}", PLUGIN_DIR);
|
||||
FileSystemUtils.mkdirs(PLUGIN_DIR);
|
||||
|
||||
// copy plugin
|
||||
copyPlugin(new File(PLUGIN_DIR, "plugin-v1"));
|
||||
copyPlugin(new File(PLUGIN_DIR, "plugin-v2"));
|
||||
}
|
||||
|
||||
private void copyPlugin(File p1) throws IOException {
|
||||
FileSystemUtils.mkdirs(p1);
|
||||
// copy plugin
|
||||
File dir = new File(p1, "org/elasticsearch/plugins/isolation/");
|
||||
FileSystemUtils.mkdirs(dir);
|
||||
copyFile(getClass().getResourceAsStream("isolation/DummyClass.class"), new File(dir, "DummyClass.class"));
|
||||
copyFile(getClass().getResourceAsStream("isolation/IsolatedPlugin.class"), new File(dir, "IsolatedPlugin.class"));
|
||||
copyFile(getClass().getResourceAsStream("isolation/es-plugin.properties"), new File(p1, "es-plugin.properties"));
|
||||
}
|
||||
|
||||
private void copyFile(InputStream source, File out) throws IOException {
|
||||
out.createNewFile();
|
||||
Streams.copy(source, new FileOutputStream(out));
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
FileSystemUtils.deleteRecursively(PLUGIN_DIR);
|
||||
}
|
||||
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
return SETTINGS;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginNumberOfIsolatedInstances() throws Exception {
|
||||
try {
|
||||
NodesInfoResponse nodesInfoResponse = client().admin().cluster().prepareNodesInfo().clear().setPlugins(true).get();
|
||||
assertThat(nodesInfoResponse.getNodes().length, equalTo(1));
|
||||
assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos(), notNullValue());
|
||||
assertThat(nodesInfoResponse.getNodes()[0].getPlugins().getInfos().size(), equalTo(2));
|
||||
} finally {
|
||||
System.setProperties(props);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsolatedPluginProperties() throws Exception {
|
||||
try {
|
||||
String prop = "es.test.isolated.plugin.count";
|
||||
int count = Integer.getInteger(prop, 0);
|
||||
client();
|
||||
// do a >= comparison in case there are multiple tests running in the same JVM (build server)
|
||||
assertThat(Integer.getInteger(prop), greaterThanOrEqualTo(count + 2));
|
||||
Properties p = System.getProperties();
|
||||
prop = p.getProperty("es.test.isolated.plugin.instantiated.hashes");
|
||||
String[] hashes = Strings.delimitedListToStringArray(prop, " ");
|
||||
// 2 plugins plus trailing space
|
||||
assertThat(hashes.length, greaterThanOrEqualTo(count + 2));
|
||||
Arrays.sort(hashes);
|
||||
assertThat(Arrays.binarySearch(hashes, p.getProperty("es.test.isolated.plugin.instantiated")), greaterThanOrEqualTo(0));
|
||||
} finally {
|
||||
System.setProperties(props);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* 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 org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
public class PluginClassLoaderTest {
|
||||
|
||||
private static final String NAME = "es.test.isolated.plugin.name";
|
||||
private static final String INSTANCE = "es.test.isolated.plugin.instantiated";
|
||||
private static final String READ = "es.test.isolated.plugin.read.name";
|
||||
|
||||
private URL root;
|
||||
private String clazz = getClass().getName().replace('.', '/').concat(".class");
|
||||
private ClassLoader parent;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
System.getProperties().setProperty(READ, "");
|
||||
System.getProperties().setProperty(NAME, "");
|
||||
System.getProperties().setProperty(INSTANCE, "");
|
||||
|
||||
parent = getClass().getClassLoader();
|
||||
URL url = parent.getResource(clazz);
|
||||
root = new URL(url.toString().substring(0, url.toString().indexOf(clazz)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassSpaceIsolationEvenWhenPointingToSameClass() throws Exception {
|
||||
|
||||
PluginClassLoader space1 = new PluginClassLoader(new URL[] { root }, null);
|
||||
Properties props = System.getProperties();
|
||||
assertThat(props.getProperty(READ), is(""));
|
||||
props.setProperty(NAME, "one");
|
||||
Class<?> class1 = Class.forName("org.elasticsearch.plugins.isolation.DummyClass", true, space1);
|
||||
assertThat(props.getProperty(READ), is("one"));
|
||||
|
||||
String instance1 = props.getProperty(INSTANCE);
|
||||
|
||||
PluginClassLoader space2 = new PluginClassLoader(new URL[] { root }, null);
|
||||
props.setProperty(NAME, "two");
|
||||
Class<?> class2 = Class.forName("org.elasticsearch.plugins.isolation.DummyClass", true, space2);
|
||||
assertThat(props.getProperty(READ), is("two"));
|
||||
|
||||
String instance2 = props.getProperty(INSTANCE);
|
||||
assertThat(instance1, not(instance2));
|
||||
assertNotSame(class1, class2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegateToParentIfResourcesNotFoundLocally() throws Exception {
|
||||
|
||||
PluginClassLoader space1 = new PluginClassLoader(new URL[] {}, null);
|
||||
assertNull(space1.getResource(clazz));
|
||||
|
||||
PluginClassLoader space2 = new PluginClassLoader(new URL[] {}, parent);
|
||||
assertNotNull(parent.getResource(clazz));
|
||||
assertNotNull(space2.getResource(clazz));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreClassesInParentIfFoundLocally() throws Exception {
|
||||
ClassLoader parent = getClass().getClassLoader();
|
||||
|
||||
PluginClassLoader space1 = new PluginClassLoader(new URL[] { root }, parent);
|
||||
|
||||
Properties props = System.getProperties();
|
||||
assertThat(props.getProperty(READ), is(""));
|
||||
props.setProperty(NAME, "one");
|
||||
|
||||
String before = props.getProperty(NAME);
|
||||
Class parentClass = Class.forName("org.elasticsearch.plugins.isolation.DummyClass", true, parent);
|
||||
props.setProperty(NAME, "one");
|
||||
Class class1 = Class.forName("org.elasticsearch.plugins.isolation.DummyClass", true, space1);
|
||||
assertThat(props.getProperty(READ), is(before));
|
||||
assertThat(class1, is(not(parentClass)));
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* 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.isolation;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class DummyClass {
|
||||
|
||||
static final String name;
|
||||
|
||||
static {
|
||||
Properties sysProps = System.getProperties();
|
||||
// make sure to get a string even when dealing with null
|
||||
name = "" + sysProps.getProperty("es.test.isolated.plugin.name");
|
||||
sysProps.setProperty("es.test.isolated.plugin.instantiated", "" + DummyClass.class.hashCode());
|
||||
Integer count = Integer.getInteger("es.test.isolated.plugin.count");
|
||||
if (count == null) {
|
||||
count = Integer.valueOf(0);
|
||||
}
|
||||
|
||||
count = count + 1;
|
||||
|
||||
sysProps.setProperty("es.test.isolated.plugin.count", count.toString());
|
||||
|
||||
String prop = sysProps.getProperty("es.test.isolated.plugin.instantiated.hashes");
|
||||
if (prop == null) {
|
||||
prop = "";
|
||||
}
|
||||
|
||||
prop = prop + DummyClass.class.hashCode() + " ";
|
||||
sysProps.setProperty("es.test.isolated.plugin.instantiated.hashes", prop);
|
||||
sysProps.setProperty("es.test.isolated.plugin.read.name", name);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* 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.isolation;
|
||||
|
||||
import org.elasticsearch.plugins.AbstractPlugin;
|
||||
|
||||
public class IsolatedPlugin extends AbstractPlugin {
|
||||
|
||||
private final DummyClass dummy;
|
||||
|
||||
public IsolatedPlugin() {
|
||||
dummy = new DummyClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return dummy.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "IsolatedPlugin " + hashCode();
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
plugin=org.elasticsearch.plugins.isolation.IsolatedPlugin
|
Loading…
Reference in New Issue