This is an automated email from the ASF dual-hosted git repository.

andor pushed a commit to branch branch-3.9
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/branch-3.9 by this push:
     new a9b19040e ZOOKEEPER-3938: Upgrade JLine to 3.25.1
a9b19040e is described below

commit a9b19040e6ebc40746ce9e752c194e3d9a1247e5
Author: Dávid Paksy <[email protected]>
AuthorDate: Wed Oct 1 17:49:28 2025 +0200

    ZOOKEEPER-3938: Upgrade JLine to 3.25.1
    
    Reviewers: anmolnar
    Author: PDavid
    Closes #2322 from PDavid/ZOOKEEPER-3938-jline-upgrade-branch-3.9
---
 pom.xml                                            |  4 +-
 zookeeper-assembly/pom.xml                         |  2 +-
 zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml |  2 +-
 zookeeper-server/pom.xml                           |  2 +-
 .../org/apache/zookeeper/JLineZNodeCompleter.java  | 46 +++++++++++-----------
 .../java/org/apache/zookeeper/ZooKeeperMain.java   | 36 ++++++++++++-----
 zookeeper-server/src/main/resources/LICENSE.txt    |  6 +--
 ...2.14.6.LICENSE.txt => jline-3.25.1.LICENSE.txt} |  7 ++--
 .../zookeeper/server/ClientSSLReloadTest.java      |  3 +-
 9 files changed, 61 insertions(+), 47 deletions(-)

diff --git a/pom.xml b/pom.xml
index d4ac91503..820cedd12 100644
--- a/pom.xml
+++ b/pom.xml
@@ -562,7 +562,7 @@
     <netty.version>4.1.127.Final</netty.version>
     <jetty.version>9.4.57.v20241219</jetty.version>
     <jackson.version>2.15.2</jackson.version>
-    <jline.version>2.14.6</jline.version>
+    <jline.version>3.25.1</jline.version>
     <snappy.version>1.1.10.5</snappy.version>
     <kerby.version>2.0.0</kerby.version>
     <bouncycastle.version>1.75</bouncycastle.version>
@@ -742,7 +742,7 @@
         <version>${jackson.version}</version>
       </dependency>
       <dependency>
-        <groupId>jline</groupId>
+        <groupId>org.jline</groupId>
         <artifactId>jline</artifactId>
         <version>${jline.version}</version>
       </dependency>
diff --git a/zookeeper-assembly/pom.xml b/zookeeper-assembly/pom.xml
index f861c2a4f..02398e48e 100755
--- a/zookeeper-assembly/pom.xml
+++ b/zookeeper-assembly/pom.xml
@@ -100,7 +100,7 @@
       <artifactId>jackson-databind</artifactId>
     </dependency>
     <dependency>
-      <groupId>jline</groupId>
+      <groupId>org.jline</groupId>
       <artifactId>jline</artifactId>
     </dependency>
     <dependency>
diff --git a/zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml 
b/zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml
index f17bb98bf..a783cf102 100755
--- a/zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml
+++ b/zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml
@@ -79,7 +79,7 @@
       <artifactId>jackson-databind</artifactId>
     </dependency>
     <dependency>
-      <groupId>jline</groupId>
+      <groupId>org.jline</groupId>
       <artifactId>jline</artifactId>
     </dependency>
     <dependency>
diff --git a/zookeeper-server/pom.xml b/zookeeper-server/pom.xml
index aa6896fe6..bc11ac52a 100755
--- a/zookeeper-server/pom.xml
+++ b/zookeeper-server/pom.xml
@@ -116,7 +116,7 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>jline</groupId>
+      <groupId>org.jline</groupId>
       <artifactId>jline</artifactId>
       <scope>provided</scope>
     </dependency>
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/JLineZNodeCompleter.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/JLineZNodeCompleter.java
index e55521400..67288e180 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/JLineZNodeCompleter.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/JLineZNodeCompleter.java
@@ -20,44 +20,41 @@
 
 import java.util.Collections;
 import java.util.List;
-import jline.console.completer.Completer;
+import org.jline.reader.Candidate;
+import org.jline.reader.Completer;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
+import org.jline.utils.AttributedString;
 
 class JLineZNodeCompleter implements Completer {
 
-    private ZooKeeper zk;
+    private final ZooKeeper zk;
 
     public JLineZNodeCompleter(ZooKeeper zk) {
         this.zk = zk;
     }
 
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public int complete(String buffer, int cursor, List candidates) {
+    @Override
+    public void complete(LineReader lineReader, ParsedLine commandLine, 
List<Candidate> candidates) {
         // Guarantee that the final token is the one we're expanding
-        buffer = buffer.substring(0, cursor);
-        String token = "";
-        if (!buffer.endsWith(" ")) {
-            String[] tokens = buffer.split(" ");
-            if (tokens.length != 0) {
-                token = tokens[tokens.length - 1];
-            }
-        }
+        String token = commandLine.words().get(commandLine.words().size() - 1);
 
         if (token.startsWith("/")) {
-            return completeZNode(buffer, token, candidates);
+            completeZNode(token, candidates);
+        } else {
+            completeCommand(token, candidates);
         }
-        return completeCommand(buffer, token, candidates);
     }
 
-    private int completeCommand(String buffer, String token, List<String> 
candidates) {
+    private void completeCommand(String token, List<Candidate> candidates) {
         for (String cmd : ZooKeeperMain.getCommands()) {
             if (cmd.startsWith(token)) {
-                candidates.add(cmd);
+                candidates.add(createCandidate(cmd));
             }
         }
-        return buffer.lastIndexOf(" ") + 1;
     }
 
-    private int completeZNode(String buffer, String token, List<String> 
candidates) {
+    private void completeZNode(String token, List<Candidate> candidates) {
         String path = token;
         int idx = path.lastIndexOf("/") + 1;
         String prefix = path.substring(idx);
@@ -67,16 +64,17 @@ private int completeZNode(String buffer, String token, 
List<String> candidates)
             List<String> children = zk.getChildren(dir, false);
             for (String child : children) {
                 if (child.startsWith(prefix)) {
-                    candidates.add(child);
+                    String zNode = dir + (idx == 1 ? "" : "/") + child;
+                    candidates.add(createCandidate(zNode));
                 }
             }
-        } catch (InterruptedException e) {
-            return 0;
-        } catch (KeeperException e) {
-            return 0;
+        } catch (InterruptedException | KeeperException e) {
+            return;
         }
         Collections.sort(candidates);
-        return candidates.size() == 0 ? buffer.length() : 
buffer.lastIndexOf("/") + 1;
     }
 
+    private static Candidate createCandidate(String cmd) {
+        return new Candidate(AttributedString.stripAnsi(cmd), cmd, null, null, 
null, null, true);
+    }
 }
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
index 07c69b445..ca27348e1 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
@@ -311,20 +311,18 @@ void run() throws IOException, InterruptedException {
             boolean jlinemissing = false;
             // only use jline if it's in the classpath
             try {
-                Class<?> consoleC = 
Class.forName("jline.console.ConsoleReader");
-                Class<?> completorC = 
Class.forName("org.apache.zookeeper.JLineZNodeCompleter");
+                Class<?> readerC = 
Class.forName("org.jline.reader.LineReader");
+                Class<?> completerC = 
Class.forName("org.apache.zookeeper.JLineZNodeCompleter");
 
                 System.out.println("JLine support is enabled");
 
-                Object console = consoleC.getConstructor().newInstance();
-
-                Object completor = 
completorC.getConstructor(ZooKeeper.class).newInstance(zk);
-                Method addCompletor = consoleC.getMethod("addCompleter", 
Class.forName("jline.console.completer.Completer"));
-                addCompletor.invoke(console, completor);
+                Object completer = 
completerC.getConstructor(ZooKeeper.class).newInstance(zk);
+                Object terminal = createTerminal();
+                Object reader = createLineReader(terminal, completer);
 
                 String line;
-                Method readLine = consoleC.getMethod("readLine", String.class);
-                while ((line = (String) readLine.invoke(console, getPrompt())) 
!= null) {
+                Method readLine = readerC.getMethod("readLine", String.class);
+                while ((line = (String) readLine.invoke(reader, getPrompt())) 
!= null) {
                     executeLine(line);
                 }
             } catch (ClassNotFoundException
@@ -353,6 +351,26 @@ void run() throws IOException, InterruptedException {
         ServiceUtils.requestSystemExit(exitCode);
     }
 
+    private static Object createTerminal() throws ClassNotFoundException, 
NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        Class<?> terminalBuilderC = 
Class.forName("org.jline.terminal.TerminalBuilder");
+        Method terminalBuilderMethod = terminalBuilderC.getMethod("builder");
+        Object terminalBuilder = terminalBuilderMethod.invoke(null);
+        Method terminalBuildMethod = terminalBuilderC.getMethod("build");
+        return terminalBuildMethod.invoke(terminalBuilder);
+    }
+
+    private static Object createLineReader(Object terminal, Object completer) 
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, 
InvocationTargetException {
+        Class<?> readerBuilderC = 
Class.forName("org.jline.reader.LineReaderBuilder");
+        Method readerBuilderMethod = readerBuilderC.getMethod("builder");
+        Object readerBuilder = readerBuilderMethod.invoke(null);
+        Method setTerminalMethod = readerBuilderC.getMethod("terminal", 
Class.forName("org.jline.terminal.Terminal"));
+        setTerminalMethod.invoke(readerBuilder, terminal);
+        Method setCompleterMethod = readerBuilderC.getMethod("completer", 
Class.forName("org.jline.reader.Completer"));
+        setCompleterMethod.invoke(readerBuilder, completer);
+        Method readerBuildMethod = readerBuilderC.getMethod("build");
+        return readerBuildMethod.invoke(readerBuilder);
+    }
+
     public void executeLine(String line) throws InterruptedException, 
IOException {
         if (!line.equals("")) {
             cl.parseCommand(line);
diff --git a/zookeeper-server/src/main/resources/LICENSE.txt 
b/zookeeper-server/src/main/resources/LICENSE.txt
index 384713a64..54d94d5b9 100644
--- a/zookeeper-server/src/main/resources/LICENSE.txt
+++ b/zookeeper-server/src/main/resources/LICENSE.txt
@@ -206,9 +206,9 @@ This distribution bundles javacc, which is available under 
the
 3-clause BSD License. For details, see a copy of the license in
 lib/javacc.LICENSE.txt
 
-This distribution bundles jline 2.14.6, which is available under the
-2-clause BSD License. For details, see a copy of the license in
-lib/jline-2.14.6.LICENSE.txt
+This distribution bundles jline 3.25.1, which is available under the
+3-clause BSD License. For details, see a copy of the license in
+lib/jline-3.25.1.LICENSE.txt
 
 This distribution bundles SLF4J 1.7.30, which is available under the MIT
 License. For details, see a copy of the license in
diff --git a/zookeeper-server/src/main/resources/lib/jline-2.14.6.LICENSE.txt 
b/zookeeper-server/src/main/resources/lib/jline-3.25.1.LICENSE.txt
similarity index 90%
rename from zookeeper-server/src/main/resources/lib/jline-2.14.6.LICENSE.txt
rename to zookeeper-server/src/main/resources/lib/jline-3.25.1.LICENSE.txt
index 4ac9522bd..ed9503f23 100644
--- a/zookeeper-server/src/main/resources/lib/jline-2.14.6.LICENSE.txt
+++ b/zookeeper-server/src/main/resources/lib/jline-3.25.1.LICENSE.txt
@@ -1,7 +1,7 @@
-Copyright (c) 2002-2012, the original author or authors.
+Copyright (c) 2002-2023, the original author or authors.
 All rights reserved.
 
-http://www.opensource.org/licenses/bsd-license.php
+https://opensource.org/licenses/BSD-3-Clause
 
 Redistribution and use in source and binary forms, with or
 without modification, are permitted provided that the following
@@ -31,5 +31,4 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-OF THE POSSIBILITY OF SUCH DAMAGE.
-
+OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/ClientSSLReloadTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/ClientSSLReloadTest.java
index c0c35c695..803ff9703 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/ClientSSLReloadTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/ClientSSLReloadTest.java
@@ -25,7 +25,6 @@
 import java.util.Properties;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import jline.internal.Log;
 import org.apache.commons.io.FileUtils;
 import org.apache.zookeeper.PortAssignment;
 import org.apache.zookeeper.WatchedEvent;
@@ -144,7 +143,7 @@ public void certficateReloadTest() throws Exception {
                 assertTrue(l.await(10, TimeUnit.SECONDS));
             }
 
-            Log.info("Updating keyStore & trustStore files !!!!");
+            LOG.info("Updating keyStore & trustStore files !!!!");
             // Update the keyStoreFile1 and trustStoreFile1 files in the 
filesystem with keyStoreFile2 & trustStoreFile2
             FileUtils.writeStringToFile(keyStoreFile1, 
FileUtils.readFileToString(keyStoreFile2, StandardCharsets.US_ASCII), 
StandardCharsets.US_ASCII, false);
             FileUtils.writeStringToFile(trustStoreFile1, 
FileUtils.readFileToString(trustStoreFile2, StandardCharsets.US_ASCII), 
StandardCharsets.US_ASCII, false);

Reply via email to