diff --git a/pom.xml b/pom.xml index b44967b126c..782a819ee31 100755 --- a/pom.xml +++ b/pom.xml @@ -439,7 +439,7 @@ 9.4.24.v20191120 2.10.3 1.1.1 - 2.14.6 + 3.16.0 1.1.7 2.0.0 1.60 @@ -635,7 +635,7 @@ - jline + org.jline jline ${jline.version} diff --git a/zookeeper-assembly/pom.xml b/zookeeper-assembly/pom.xml index 8a2967fe616..4b6525e17cd 100755 --- a/zookeeper-assembly/pom.xml +++ b/zookeeper-assembly/pom.xml @@ -104,7 +104,7 @@ json-simple - jline + org.jline jline diff --git a/zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml b/zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml index 9a90dd7fc3c..9e38ab31c55 100755 --- a/zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml +++ b/zookeeper-contrib/zookeeper-contrib-fatjar/pom.xml @@ -83,7 +83,7 @@ json-simple - jline + org.jline jline diff --git a/zookeeper-server/pom.xml b/zookeeper-server/pom.xml index 059f2fff0fb..b4355cf0d56 100755 --- a/zookeeper-server/pom.xml +++ b/zookeeper-server/pom.xml @@ -113,7 +113,7 @@ test - jline + org.jline jline provided 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 e55521400fa..e863f27c802 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/JLineZNodeCompleter.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/JLineZNodeCompleter.java @@ -20,20 +20,21 @@ 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; class JLineZNodeCompleter implements Completer { - private ZooKeeper zk; public JLineZNodeCompleter(ZooKeeper zk) { this.zk = zk; } - @SuppressWarnings({"unchecked", "rawtypes"}) - public int complete(String buffer, int cursor, List candidates) { - // Guarantee that the final token is the one we're expanding - buffer = buffer.substring(0, cursor); + @Override + public void complete(LineReader reader, ParsedLine commandLine, List candidates) { + String buffer = commandLine.word().substring(0, commandLine.wordCursor()); String token = ""; if (!buffer.endsWith(" ")) { String[] tokens = buffer.split(" "); @@ -43,40 +44,38 @@ public int complete(String buffer, int cursor, List candidates) { } if (token.startsWith("/")) { - return completeZNode(buffer, token, candidates); - } - return completeCommand(buffer, token, candidates); - } - - private int completeCommand(String buffer, String token, List candidates) { - for (String cmd : ZooKeeperMain.getCommands()) { - if (cmd.startsWith(token)) { - candidates.add(cmd); - } + completeZNode(candidates, token); + } else { + completeCommand(candidates, token); } - return buffer.lastIndexOf(" ") + 1; } - private int completeZNode(String buffer, String token, List candidates) { - String path = token; - int idx = path.lastIndexOf("/") + 1; - String prefix = path.substring(idx); + private void completeZNode(List candidates, String token) { + int idx = token.lastIndexOf("/") + 1; + String prefix = token.substring(idx); try { // Only the root path can end in a /, so strip it off every other prefix - String dir = idx == 1 ? "/" : path.substring(0, idx - 1); - List children = zk.getChildren(dir, false); + StringBuilder dir = new StringBuilder(idx == 1 ? "/" : token.substring(0, idx - 1)); + List children = zk.getChildren(dir.toString(), false); for (String child : children) { if (child.startsWith(prefix)) { - candidates.add(child); + if (!dir.toString().endsWith("/")) { + dir.append("/"); + } + candidates.add(new Candidate(dir + child, child, null, null, null, null, true)); } } - } catch (InterruptedException e) { - return 0; - } catch (KeeperException e) { - return 0; + } catch (InterruptedException | KeeperException e) { + // Ignore } Collections.sort(candidates); - return candidates.size() == 0 ? buffer.length() : buffer.lastIndexOf("/") + 1; } + private void completeCommand(List candidates, String token) { + for (String cmd : ZooKeeperMain.getCommands()) { + if (cmd.startsWith(token)) { + candidates.add(new Candidate(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 ff8ce623286..cdfba365868 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java @@ -18,11 +18,7 @@ package org.apache.zookeeper; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -46,6 +42,12 @@ import org.apache.zookeeper.server.ExitCode; import org.apache.zookeeper.server.quorum.QuorumPeerConfig; import org.apache.zookeeper.util.ServiceUtils; +import org.jline.reader.Completer; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.UserInterruptException; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -282,44 +284,21 @@ public ZooKeeperMain(ZooKeeper zk) { void run() throws IOException, InterruptedException { if (cl.getCommand() == null) { System.out.println("Welcome to ZooKeeper!"); + System.out.println("JLine support is enabled"); - 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"); - - System.out.println("JLine support is enabled"); - - Object console = consoleC.getConstructor().newInstance(); + Terminal terminal = TerminalBuilder.builder().system(true).build(); + Completer znodeCompleter = new JLineZNodeCompleter(zk); - Object completor = completorC.getConstructor(ZooKeeper.class).newInstance(zk); - Method addCompletor = consoleC.getMethod("addCompleter", Class.forName("jline.console.completer.Completer")); - addCompletor.invoke(console, completor); + LineReader lineReader = LineReaderBuilder.builder().terminal(terminal).completer(znodeCompleter).build(); - String line; - Method readLine = consoleC.getMethod("readLine", String.class); - while ((line = (String) readLine.invoke(console, getPrompt())) != null) { - executeLine(line); - } - } catch (ClassNotFoundException - | NoSuchMethodException - | InvocationTargetException - | IllegalAccessException - | InstantiationException e - ) { - LOG.debug("Unable to start jline", e); - jlinemissing = true; - } - - if (jlinemissing) { - System.out.println("JLine support is disabled"); - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - - String line; - while ((line = br.readLine()) != null) { + String line; + try { + while ((line = lineReader.readLine(getPrompt())) != null) { executeLine(line); } + } catch (UserInterruptException ex) { + // ignore exception + executeLine("quit"); } } else { // Command line args non-null. Run what was passed. diff --git a/zookeeper-server/src/main/resources/lib/jline-2.14.6.LICENSE.txt b/zookeeper-server/src/main/resources/lib/jline-3.16.0.LICENSE.txt similarity index 92% rename from zookeeper-server/src/main/resources/lib/jline-2.14.6.LICENSE.txt rename to zookeeper-server/src/main/resources/lib/jline-3.16.0.LICENSE.txt index 4ac9522bd8c..7e11b67fba7 100644 --- a/zookeeper-server/src/main/resources/lib/jline-2.14.6.LICENSE.txt +++ b/zookeeper-server/src/main/resources/lib/jline-3.16.0.LICENSE.txt @@ -1,7 +1,7 @@ -Copyright (c) 2002-2012, the original author or authors. +Copyright (c) 2002-2018, 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