diff --git a/core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java b/core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java index ecd26673919..0d8ef345336 100644 --- a/core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java +++ b/core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java @@ -179,6 +179,9 @@ public class Bootstrap { // install any plugins into classpath setupPlugins(environment); + // look for jar hell + JarHell.checkJarHell(); + // install SM after natives, shutdown hooks, etc. setupSecurity(settings, environment); @@ -375,7 +378,8 @@ public class Bootstrap { return; } - ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + // note: there's only one classloader here, but Uwe gets upset otherwise. + ClassLoader classLoader = Bootstrap.class.getClassLoader(); Class classLoaderClass = classLoader.getClass(); Method addURL = null; while (!classLoaderClass.equals(Object.class)) { diff --git a/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java b/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java new file mode 100644 index 00000000000..5ab6350e729 --- /dev/null +++ b/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java @@ -0,0 +1,102 @@ +/* + * 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.bootstrap; + +import org.elasticsearch.common.SuppressForbidden; +import org.elasticsearch.common.io.PathUtils; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** Simple check for duplicate class files across the classpath */ +class JarHell { + + /** + * Checks the current classloader for duplicate classes + * @throws IllegalStateException if jar hell was found + */ + @SuppressForbidden(reason = "needs JarFile for speed, just reading entries") + static void checkJarHell() throws Exception { + ClassLoader loader = JarHell.class.getClassLoader(); + if (loader instanceof URLClassLoader == false) { + return; + } + final Map clazzes = new HashMap<>(32768); + Set seenJars = new HashSet<>(); + for (final URL url : ((URLClassLoader)loader).getURLs()) { + String path = url.getPath(); + if (path.endsWith(".jar")) { + if (!seenJars.add(path)) { + continue; // we can't fail because of sheistiness with joda-time + } + try (JarFile file = new JarFile(url.getPath())) { + Enumeration elements = file.entries(); + while (elements.hasMoreElements()) { + String entry = elements.nextElement().getName(); + if (entry.endsWith(".class")) { + checkClass(clazzes, entry, url); + } + } + } + } else { + Files.walkFileTree(PathUtils.get(url.toURI()), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + String entry = file.toString(); + if (entry.endsWith(".class")) { + checkClass(clazzes, entry, url); + } + return super.visitFile(file, attrs); + } + }); + } + } + } + + @SuppressForbidden(reason = "proper use of URL to reduce noise") + static void checkClass(Map clazzes, String clazz, URL url) { + if (clazz.startsWith("org/apache/log4j")) { + return; // go figure, jar hell for what should be System.out.println... + } + if (clazz.equals("org/joda/time/base/BaseDateTime.class")) { + return; // apparently this is intentional... clean this up + } + URL previous = clazzes.put(clazz, url); + if (previous != null) { + throw new IllegalStateException("jar hell!" + System.lineSeparator() + + "class: " + clazz + System.lineSeparator() + + "jar1: " + previous.getPath() + System.lineSeparator() + + "jar2: " + url.getPath()); + } + } +} diff --git a/core/src/main/java/org/elasticsearch/bootstrap/Security.java b/core/src/main/java/org/elasticsearch/bootstrap/Security.java index 6bd000e37e4..3e4391aceac 100644 --- a/core/src/main/java/org/elasticsearch/bootstrap/Security.java +++ b/core/src/main/java/org/elasticsearch/bootstrap/Security.java @@ -81,7 +81,7 @@ final class Security { */ @SuppressForbidden(reason = "proper use of URL") static void setCodebaseProperties() { - ClassLoader loader = ClassLoader.getSystemClassLoader(); + ClassLoader loader = Security.class.getClassLoader(); if (loader instanceof URLClassLoader) { for (URL url : ((URLClassLoader)loader).getURLs()) { for (Map.Entry e : SPECIAL_JARS.entrySet()) { diff --git a/core/src/test/java/org/elasticsearch/action/bulk/BulkProcessorTests.java b/core/src/test/java/org/elasticsearch/action/bulk/BulkProcessorTests.java index ad1e9d97719..358ffb820f9 100644 --- a/core/src/test/java/org/elasticsearch/action/bulk/BulkProcessorTests.java +++ b/core/src/test/java/org/elasticsearch/action/bulk/BulkProcessorTests.java @@ -19,7 +19,7 @@ package org.elasticsearch.action.bulk; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.carrotsearch.randomizedtesting.generators.RandomPicks; +import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.elasticsearch.action.get.MultiGetItemResponse; import org.elasticsearch.action.get.MultiGetRequestBuilder; diff --git a/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java b/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java index 56d6e42fd4d..1fbb1462ac6 100644 --- a/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java +++ b/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java @@ -50,6 +50,13 @@ public class BootstrapForTesting { static { // just like bootstrap, initialize natives, then SM Bootstrap.initializeNatives(true, true, true); + + // check for jar hell + try { + JarHell.checkJarHell(); + } catch (Exception e) { + throw new RuntimeException("found jar hell in test classpath", e); + } // make sure java.io.tmpdir exists always (in case code uses it in a static initializer) Path javaTmpDir = PathUtils.get(Objects.requireNonNull(System.getProperty("java.io.tmpdir"), diff --git a/core/src/test/java/org/elasticsearch/client/node/NodeClientHeadersTests.java b/core/src/test/java/org/elasticsearch/client/node/NodeClientHeadersTests.java index be2df27197b..429cafdef54 100644 --- a/core/src/test/java/org/elasticsearch/client/node/NodeClientHeadersTests.java +++ b/core/src/test/java/org/elasticsearch/client/node/NodeClientHeadersTests.java @@ -19,10 +19,12 @@ package org.elasticsearch.client.node; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSet; + import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.GenericAction; +import org.elasticsearch.action.support.ActionFilter; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.TransportAction; import org.elasticsearch.client.AbstractClientHeadersTests; @@ -31,6 +33,7 @@ import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.threadpool.ThreadPool; +import java.util.Collections; import java.util.HashMap; /** @@ -38,7 +41,7 @@ import java.util.HashMap; */ public class NodeClientHeadersTests extends AbstractClientHeadersTests { - private static final ActionFilters EMPTY_FILTERS = new ActionFilters(ImmutableSet.of()); + private static final ActionFilters EMPTY_FILTERS = new ActionFilters(Collections.emptySet()); @Override protected Client buildClient(Settings headersSettings, GenericAction[] testedActions) { diff --git a/core/src/test/java/org/elasticsearch/common/collect/CopyOnWriteHashMapTests.java b/core/src/test/java/org/elasticsearch/common/collect/CopyOnWriteHashMapTests.java index f86f4cf8556..6cdde469418 100644 --- a/core/src/test/java/org/elasticsearch/common/collect/CopyOnWriteHashMapTests.java +++ b/core/src/test/java/org/elasticsearch/common/collect/CopyOnWriteHashMapTests.java @@ -19,7 +19,7 @@ package org.elasticsearch.common.collect; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap; import org.elasticsearch.test.ElasticsearchTestCase; import java.util.HashMap; diff --git a/core/src/test/java/org/elasticsearch/common/lucene/index/FreqTermsEnumTests.java b/core/src/test/java/org/elasticsearch/common/lucene/index/FreqTermsEnumTests.java index 02468f98cee..840ebd8e9b8 100644 --- a/core/src/test/java/org/elasticsearch/common/lucene/index/FreqTermsEnumTests.java +++ b/core/src/test/java/org/elasticsearch/common/lucene/index/FreqTermsEnumTests.java @@ -19,8 +19,8 @@ package org.elasticsearch.common.lucene.index; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.Lists; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.Maps; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.lucene.analysis.core.KeywordAnalyzer; diff --git a/core/src/test/java/org/elasticsearch/index/store/CorruptedFileTest.java b/core/src/test/java/org/elasticsearch/index/store/CorruptedFileTest.java index f98a775dfe8..0ee11bdce53 100644 --- a/core/src/test/java/org/elasticsearch/index/store/CorruptedFileTest.java +++ b/core/src/test/java/org/elasticsearch/index/store/CorruptedFileTest.java @@ -18,10 +18,11 @@ */ package org.elasticsearch.index.store; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.Lists; import com.carrotsearch.randomizedtesting.generators.RandomPicks; import com.google.common.base.Charsets; import com.google.common.base.Predicate; +import com.google.common.collect.Lists; + import org.apache.lucene.codecs.CodecUtil; import org.apache.lucene.index.CheckIndex; import org.apache.lucene.index.IndexFileNames; diff --git a/core/src/test/java/org/elasticsearch/index/store/CorruptedTranslogTests.java b/core/src/test/java/org/elasticsearch/index/store/CorruptedTranslogTests.java index b03c7d90327..ae37466981b 100644 --- a/core/src/test/java/org/elasticsearch/index/store/CorruptedTranslogTests.java +++ b/core/src/test/java/org/elasticsearch/index/store/CorruptedTranslogTests.java @@ -19,7 +19,7 @@ package org.elasticsearch.index.store; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.Lists; +import com.google.common.collect.Lists; import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse; diff --git a/core/src/test/java/org/elasticsearch/test/XContentTestUtils.java b/core/src/test/java/org/elasticsearch/test/XContentTestUtils.java index 1f1b8eff710..917c66a452b 100644 --- a/core/src/test/java/org/elasticsearch/test/XContentTestUtils.java +++ b/core/src/test/java/org/elasticsearch/test/XContentTestUtils.java @@ -19,7 +19,7 @@ package org.elasticsearch.test; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.Lists; +import com.google.common.collect.Lists; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; diff --git a/core/src/test/java/org/elasticsearch/transport/ContextAndHeaderTransportTests.java b/core/src/test/java/org/elasticsearch/transport/ContextAndHeaderTransportTests.java index db9219785c8..40cb626ce93 100644 --- a/core/src/test/java/org/elasticsearch/transport/ContextAndHeaderTransportTests.java +++ b/core/src/test/java/org/elasticsearch/transport/ContextAndHeaderTransportTests.java @@ -19,7 +19,6 @@ package org.elasticsearch.transport; -import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.ImmutableList; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.elasticsearch.action.*; @@ -380,7 +379,9 @@ public class ContextAndHeaderTransportTests extends ElasticsearchIntegrationTest @Override public Collection> modules() { - return ImmutableList.of(ActionLoggingModule.class); + Collection> classes = new ArrayList<>(); + classes.add(ActionLoggingModule.class); + return classes; } } diff --git a/plugins/pom.xml b/plugins/pom.xml index 00706f9c088..b40ebb74fac 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -29,11 +29,6 @@ hamcrest-all test - - junit - junit - test - org.apache.lucene lucene-test-framework diff --git a/pom.xml b/pom.xml index 31262ac3a82..b637996bb0e 100644 --- a/pom.xml +++ b/pom.xml @@ -163,6 +163,13 @@ org.apache.lucene lucene-test-framework ${lucene.maven.version} + + + + com.carrotsearch.randomizedtesting + junit4-ant + +