From 488944f4a1ddf2be89f8098218578f6112d4d3fe Mon Sep 17 00:00:00 2001 From: Andrei Stefan Date: Fri, 7 Feb 2020 04:15:59 +0200 Subject: [PATCH] SQL: Handle uberjar scenario where the ES jdbc driver file is bundled in another jar (#51856) (#52024) (cherry picked from commit 6247b0793c9db19a8a9fa6f0164cc14d0debed6e) --- .../xpack/sql/client/Version.java | 33 +++++++---- .../xpack/sql/client/VersionTests.java | 55 ++++++++++++++++++- 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/x-pack/plugin/sql/sql-client/src/main/java/org/elasticsearch/xpack/sql/client/Version.java b/x-pack/plugin/sql/sql-client/src/main/java/org/elasticsearch/xpack/sql/client/Version.java index 3f7134272c9..93db1b50636 100644 --- a/x-pack/plugin/sql/sql-client/src/main/java/org/elasticsearch/xpack/sql/client/Version.java +++ b/x-pack/plugin/sql/sql-client/src/main/java/org/elasticsearch/xpack/sql/client/Version.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.sql.client; import java.io.IOException; import java.net.URL; +import java.net.URLConnection; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashSet; @@ -86,26 +87,34 @@ public class Version { // This is similar to how Elasticsearch's Build class digs up its build information. // Since version info is not critical, the parsing is lenient URL url = Version.class.getProtectionDomain().getCodeSource().getLocation(); - String urlStr = url.toString(); + CURRENT = extractVersion(url); + } + static Version extractVersion(URL url) { + String urlStr = url.toString(); byte maj = 0, min = 0, rev = 0; String ver = "Unknown"; String hash = ver; - - if (urlStr.endsWith(".jar")) { - try (JarInputStream jar = new JarInputStream(url.openStream())) { - Manifest manifest = jar.getManifest(); - hash = manifest.getMainAttributes().getValue("Change"); - ver = manifest.getMainAttributes().getValue("X-Compile-Elasticsearch-Version"); - byte[] vers = from(ver); - maj = vers[0]; - min = vers[1]; - rev = vers[2]; + + if (urlStr.endsWith(".jar") || urlStr.endsWith(".jar!/")) { + try { + URLConnection conn = url.openConnection(); + conn.setUseCaches(false); + + try (JarInputStream jar = new JarInputStream(conn.getInputStream())) { + Manifest manifest = jar.getManifest(); + hash = manifest.getMainAttributes().getValue("Change"); + ver = manifest.getMainAttributes().getValue("X-Compile-Elasticsearch-Version"); + byte[] vers = from(ver); + maj = vers[0]; + min = vers[1]; + rev = vers[2]; + } } catch (Exception ex) { throw new IllegalArgumentException("Detected Elasticsearch JDBC jar but cannot retrieve its version", ex); } } - CURRENT = new Version(ver, hash, maj, min, rev); + return new Version(ver, hash, maj, min, rev); } @Override diff --git a/x-pack/plugin/sql/sql-client/src/test/java/org/elasticsearch/xpack/sql/client/VersionTests.java b/x-pack/plugin/sql/sql-client/src/test/java/org/elasticsearch/xpack/sql/client/VersionTests.java index 7ed772e3525..03979a0a2b4 100644 --- a/x-pack/plugin/sql/sql-client/src/test/java/org/elasticsearch/xpack/sql/client/VersionTests.java +++ b/x-pack/plugin/sql/sql-client/src/test/java/org/elasticsearch/xpack/sql/client/VersionTests.java @@ -6,7 +6,17 @@ package org.elasticsearch.xpack.sql.client; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.sql.client.Version; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; public class VersionTests extends ESTestCase { public void test70Version() { @@ -43,4 +53,47 @@ public class VersionTests extends ESTestCase { IllegalArgumentException err = expectThrows(IllegalArgumentException.class, () -> Version.from("7.1")); assertEquals("Invalid version 7.1", err.getMessage()); } + + public void testVersionFromJarInJar() throws IOException { + final String JDBC_JAR_NAME = "es-sql-jdbc.jar"; + final String JAR_PATH_SEPARATOR = "!/"; + + Path dir = createTempDir(); + Path jarPath = dir.resolve("uberjar.jar"); // simulated uberjar containing the jdbc driver + Path innerJarPath = dir.resolve(JDBC_JAR_NAME); // simulated ES JDBC driver file + + Manifest jdbcJarManifest = new Manifest(); + Attributes attributes = jdbcJarManifest.getMainAttributes(); + attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0.0"); + attributes.put(new Attributes.Name("Change"), "abc"); + attributes.put(new Attributes.Name("X-Compile-Elasticsearch-Version"), "1.2.3"); + + // create the jdbc driver file + try (JarOutputStream jdbc = new JarOutputStream(Files.newOutputStream(innerJarPath, StandardOpenOption.CREATE), jdbcJarManifest)) {} + + // create the uberjar and embed the jdbc driver one into it + try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(innerJarPath)); + JarOutputStream out = new JarOutputStream(Files.newOutputStream(jarPath, StandardOpenOption.CREATE), new Manifest())) { + JarEntry entry = new JarEntry(JDBC_JAR_NAME + JAR_PATH_SEPARATOR); + out.putNextEntry(entry); + + byte[] buffer = new byte[1024]; + while (true) { + int count = in.read(buffer); + if (count == -1) { + break; + } + out.write(buffer, 0, count); + } + } + + URL jarInJar = new URL("jar:" + jarPath.toUri().toURL().toString() + JAR_PATH_SEPARATOR + JDBC_JAR_NAME + JAR_PATH_SEPARATOR); + + Version version = Version.extractVersion(jarInJar); + assertEquals(1, version.major); + assertEquals(2, version.minor); + assertEquals(3, version.revision); + assertEquals("abc", version.hash); + assertEquals("1.2.3", version.version); + } }