diff --git a/appserver/admin/cli/pom.xml b/appserver/admin/cli/pom.xml index ca2c0d45ba6..5ff656a01b0 100755 --- a/appserver/admin/cli/pom.xml +++ b/appserver/admin/cli/pom.xml @@ -39,9 +39,8 @@ only if the new code is made subject to such option by the copyright holder. - Portions Copyright [2019] [Payara Foundation and/or its affiliates] --> - + 4.0.0 @@ -78,7 +77,7 @@ org.glassfish.admin.cli.AsadminMain - ../../modules/admin-cli.jar ../../modules/jaxb-osgi.jar ../../modules/istack-commons-runtime.jar + ../../modules/admin-cli.jar ../../modules/jaxb-osgi.jar ../../modules/istack-commons-runtime.jar jna.jar jline-terminal-jna.jar diff --git a/appserver/packager/glassfish-common-web/pom.xml b/appserver/packager/glassfish-common-web/pom.xml index aa52e49c460..1c85a552aa5 100644 --- a/appserver/packager/glassfish-common-web/pom.xml +++ b/appserver/packager/glassfish-common-web/pom.xml @@ -176,6 +176,16 @@ appserver-cli ${project.version} + + net.java.dev.jna + jna + ${jna.version} + + + org.jline + jline-terminal-jna + ${jline-terminal-jna} + org.glassfish.main.admin admin-core diff --git a/appserver/packager/glassfish-common-web/src/main/assembly/glassfish-common-web.xml b/appserver/packager/glassfish-common-web/src/main/assembly/glassfish-common-web.xml index 8577880afb1..de1e12ed8d0 100644 --- a/appserver/packager/glassfish-common-web/src/main/assembly/glassfish-common-web.xml +++ b/appserver/packager/glassfish-common-web/src/main/assembly/glassfish-common-web.xml @@ -40,6 +40,7 @@ holder. --> + @@ -57,6 +58,8 @@ modules/cli-optional.jar modules/appserver-cli.jar + modules/jna.jar + modules/jline-terminal-jna.jar bin/* pkg_proto.py @@ -81,6 +84,8 @@ ${install.dir.name}/glassfish/lib/client appserver-cli.jar + jna.jar + jline-terminal-jna.jar diff --git a/appserver/pom.xml b/appserver/pom.xml index fab481acd08..1e5fbcca122 100644 --- a/appserver/pom.xml +++ b/appserver/pom.xml @@ -138,6 +138,10 @@ 2.0.1 + 5.2.0 + + 3.11.0 + 5.1.1.final.payara-p4 diff --git a/appserver/tests/quicklook/ejb/mdb/create_resources.asadmin b/appserver/tests/quicklook/ejb/mdb/create_resources.asadmin index 5c11aa84d0a..5f6819b5c99 100755 --- a/appserver/tests/quicklook/ejb/mdb/create_resources.asadmin +++ b/appserver/tests/quicklook/ejb/mdb/create_resources.asadmin @@ -42,3 +42,4 @@ create-jmsdest --desttype queue ejb_ejb30_hello_mdb_InQueue create-jms-resource --restype javax.jms.Queue --property imqDestinationName=ejb_ejb30_hello_mdb_InQueue jms/ejb_ejb30_hello_mdb_InQueue create-jmsdest --desttype queue ejb_ejb30_hello_mdb_OutQueue create-jms-resource --restype javax.jms.Queue --property imqDestinationName=ejb_ejb30_hello_mdb_OutQueue jms/ejb_ejb30_hello_mdb_OutQueue + diff --git a/nucleus/admin/cli/pom.xml b/nucleus/admin/cli/pom.xml index 86e09a54ac1..e14004bc41f 100755 --- a/nucleus/admin/cli/pom.xml +++ b/nucleus/admin/cli/pom.xml @@ -166,7 +166,7 @@ ${project.version} - jline + org.jline jline diff --git a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/CLICommand.java b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/CLICommand.java index c907cc0e4eb..9991eb59ffd 100644 --- a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/CLICommand.java +++ b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/CLICommand.java @@ -37,45 +37,50 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2018] Payara Foundation and/or affiliates +// Portions Copyright [2018-2019] Payara Foundation and/or affiliates package com.sun.enterprise.admin.cli; +import com.sun.appserv.server.util.Version; +import com.sun.enterprise.admin.cli.remote.RemoteCLICommand; +import com.sun.enterprise.admin.cli.remote.RemoteCommand; +import com.sun.enterprise.admin.util.CommandModelData.ParamModelData; +import com.sun.enterprise.admin.util.LineTokenReplacer; +import com.sun.enterprise.admin.util.TokenValue; +import com.sun.enterprise.admin.util.TokenValueSet; +import com.sun.enterprise.universal.glassfish.ASenvPropertyReader; +import com.sun.enterprise.universal.i18n.LocalStringsImpl; import java.io.*; -import java.util.*; import java.lang.annotation.Annotation; -import java.util.logging.*; - -import jline.console.ConsoleReader; -import org.jvnet.hk2.annotations.Contract; -import org.jvnet.hk2.annotations.Service; -import org.jvnet.hk2.config.InjectionManager; -import org.jvnet.hk2.config.InjectionResolver; -import org.jvnet.hk2.config.UnsatisfiedDependencyException; - +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.inject.Inject; +import javax.inject.Scope; +import javax.inject.Singleton; import org.glassfish.api.Param; -import org.glassfish.api.admin.*; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandModel; import org.glassfish.api.admin.CommandModel.ParamModel; +import org.glassfish.api.admin.CommandValidationException; +import org.glassfish.api.admin.ParameterMap; import org.glassfish.common.util.admin.CommandModelImpl; -import org.glassfish.common.util.admin.MapInjectionResolver; import org.glassfish.common.util.admin.ManPageFinder; +import org.glassfish.common.util.admin.MapInjectionResolver; import org.glassfish.hk2.api.PerLookup; import org.glassfish.hk2.api.PostConstruct; import org.glassfish.hk2.api.ServiceLocator; - -import com.sun.enterprise.admin.util.CommandModelData.ParamModelData; -import com.sun.enterprise.admin.cli.remote.RemoteCommand; -import com.sun.enterprise.admin.util.LineTokenReplacer; -import com.sun.enterprise.admin.util.TokenValue; -import com.sun.enterprise.admin.util.TokenValueSet; -import com.sun.enterprise.universal.i18n.LocalStringsImpl; -import com.sun.enterprise.universal.glassfish.ASenvPropertyReader; -import com.sun.appserv.server.util.Version; -import com.sun.enterprise.admin.cli.remote.RemoteCLICommand; - -import javax.inject.Inject; -import javax.inject.Scope; -import javax.inject.Singleton; +import org.jline.reader.EndOfFileException; +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.jvnet.hk2.annotations.Contract; +import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.InjectionManager; +import org.jvnet.hk2.config.InjectionResolver; +import org.jvnet.hk2.config.UnsatisfiedDependencyException; /** @@ -105,6 +110,10 @@ public abstract class CLICommand implements PostConstruct { public static final int INVALID_COMMAND_ERROR = 3; public static final int SUCCESS = CLIConstants.SUCCESS; public static final int WARNING = CLIConstants.WARNING; + + protected Terminal terminal; + protected LineReader lineReader; + protected static final String ASADMIN = "asadmin"; private static final Set unsupported; private static final String UNSUPPORTED_CMD_FILE_NAME = "unsupported-legacy-command-names"; @@ -132,10 +141,6 @@ public abstract class CLICommand implements PostConstruct { "product---name", // the product name }; private String manpageTokenValues[] = new String[manpageTokens.length]; - - static{ - checkToDisableJLineLogging(); - } /** * The name of the command. @@ -284,6 +289,12 @@ protected CLICommand(String name, ProgramOptions programOpts, Environment env) { initializeLogger(); } + public int execute(Terminal terminal, String... argv) throws CommandException { + if (terminal != null) { + this.terminal = terminal; + } + return execute(argv); + } /** * Execute this command with the given arguemnts. * The implementation in this class saves the passed arguments in @@ -297,7 +308,7 @@ protected CLICommand(String name, ProgramOptions programOpts, Environment env) { * @throws CommandException if execution of the command fails * @throws CommandValidationException if there's something wrong * with the options or arguments - */ + */ public int execute(String... argv) throws CommandException { this.argv = argv; initializePasswords(); @@ -915,90 +926,82 @@ protected void prevalidate() throws CommandException { /* * Check for missing options and operands. */ - ConsoleReader cons = null; + if (programOpts.isInteractive()) { try { - cons = new ConsoleReader(System.in, System.out, null); - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error instantiating console", ioe); - } - } - - boolean missingOption = false; - for (ParamModel opt : commandModel.getParameters()) { - if (opt.getParam().password()) - continue; // passwords are handled later - if (opt.getParam().obsolete() && getOption(opt.getName()) != null) { - logger.info(strings.get("ObsoleteOption", opt.getName())); - } - if (opt.getParam().optional()) { - continue; - } - if (opt.getParam().primary()) { - continue; - } - // if option isn't set, prompt for it (if interactive) - if (getOption(opt.getName()) == null && cons != null && !missingOption) { - cons.setPrompt(strings.get("optionPrompt", lc(opt.getName()))); - try { - String val = cons.readLine(); - if (ok(val)) { - options.set(opt.getName(), val); + buildTerminal(); + buildLineReader(); + boolean missingOption = false; + for (ParamModel opt : commandModel.getParameters()) { + if (opt.getParam().password()) { + continue; // passwords are handled later + } + if (opt.getParam().obsolete() && getOption(opt.getName()) != null) { + logger.info(strings.get("ObsoleteOption", opt.getName())); + } + if (opt.getParam().optional()) { + continue; + } + if (opt.getParam().primary()) { + continue; + } + // if option isn't set, prompt for it (if interactive) + if (getOption(opt.getName()) == null && lineReader != null && !missingOption) { + String val = lineReader.readLine(strings.get("optionPrompt", lc(opt.getName()))); + if (ok(val)) { + options.set(opt.getName(), val); + } + } + // if it's still not set, that's an error + if (getOption(opt.getName()) == null) { + missingOption = true; + logger.log(Level.INFO, strings.get("missingOption", "--" + opt.getName())); + } + if (opt.getParam().obsolete()) { // a required obsolete option? + logger.log(Level.INFO, strings.get("ObsoleteOption", opt.getName())); } - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); } - } - // if it's still not set, that's an error - if (getOption(opt.getName()) == null) { - missingOption = true; - logger.log(Level.INFO, strings.get("missingOption", "--" + opt.getName())); - } - if (opt.getParam().obsolete()) { // a required obsolete option? - logger.log(Level.INFO, strings.get("ObsoleteOption", opt.getName())); - } - } - if (missingOption) { - throw new CommandValidationException(strings.get("missingOptions", name)); - } + if (missingOption) { + throw new CommandValidationException(strings.get("missingOptions", name)); + } - int operandMin = 0; - int operandMax = 0; - ParamModel operandParam = getOperandModel(); - if (operandParam != null) { - operandMin = operandParam.getParam().optional() ? 0 : 1; - operandMax = operandParam.getParam().multiple() ? Integer.MAX_VALUE : 1; - } + int operandMin = 0; + int operandMax = 0; + ParamModel operandParam = getOperandModel(); + if (operandParam != null) { + operandMin = operandParam.getParam().optional() ? 0 : 1; + operandMax = operandParam.getParam().multiple() ? Integer.MAX_VALUE : 1; + } - if (operands.size() < operandMin && cons != null) { - cons.setPrompt(strings.get("operandPrompt", operandParam.getName())); - try { - String val = cons.readLine(); - if (ok(val)) { - operands = new ArrayList(); - operands.add(val); + if (operands.size() < operandMin && lineReader != null) { + String val = lineReader.readLine(strings.get("operandPrompt", operandParam.getName())); + if (ok(val)) { + operands = new ArrayList<>(); + operands.add(val); + } } - } catch (IOException ioe) { - throw new CommandValidationException("Error reading input", ioe); - } - } - if (operands.size() < operandMin) { - throw new CommandValidationException(strings.get("notEnoughOperands", name, operandParam.getType())); - } - if (operands.size() > operandMax) { - switch (operandMax) { - case 0: - throw new CommandValidationException( - strings.get("noOperandsAllowed", name)); - case 1: - throw new CommandValidationException( - strings.get("tooManyOperands1", name)); - default: - throw new CommandValidationException( - strings.get("tooManyOperands", name, operandMax)); + if (operands.size() < operandMin) { + throw new CommandValidationException(strings.get("notEnoughOperands", name, operandParam.getType())); + } + if (operands.size() > operandMax) { + switch (operandMax) { + case 0: + throw new CommandValidationException( + strings.get("noOperandsAllowed", name)); + case 1: + throw new CommandValidationException( + strings.get("tooManyOperands1", name)); + default: + throw new CommandValidationException( + strings.get("tooManyOperands", name, operandMax)); + } + } + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + } finally { + closeTerminal(); } } - initializeCommandPassword(); } @@ -1210,20 +1213,18 @@ private String passwordName(ParamModel opt) { * @return */ protected char[] readPassword(String prompt) { - char[] pc = null; - - try (ConsoleReader consoleReader = new ConsoleReader(System.in, System.out, null)) { - // Don't echo anything when reading + try { + buildTerminal(); + buildLineReader(); char echoCharacter = 0; - consoleReader.setEchoCharacter(echoCharacter); - - String line = consoleReader.readLine(prompt); - pc = line.toCharArray(); - } catch (IOException ioe) { - logger.log(Level.WARNING, "IOException reading password.", ioe); + String line = lineReader.readLine(prompt, echoCharacter); + return line.toCharArray(); + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + } finally { + closeTerminal(); } - - return pc; + return null; } /** @@ -1392,16 +1393,37 @@ private static void file2Set(String file, Set set) { } } - private static void checkToDisableJLineLogging(){ - if (Boolean.getBoolean("fish.payara.admin.command.jline.log.disable")) { - System.setProperty("jline.log.jul", "false"); - final OutputStream noOpOutputStream = new OutputStream() { - @Override - public void write(int b) throws IOException { - //NO-OP + protected void buildTerminal() { + try { + if (terminal == null) { + terminal = TerminalBuilder.builder() + .system(true) + .build(); + } + } catch (IOException ioe) { + logger.log(Level.WARNING, "Error building a Terminal", ioe); + } + } + + protected void buildLineReader() { + if (lineReader == null) { + lineReader = LineReaderBuilder.builder() + .terminal(terminal) + .build(); + } + } + + protected void closeTerminal() { + try { + if (terminal != null) { + if (!terminal.getName().equals(ASADMIN)) { + terminal.close(); + terminal = null; } - }; - jline.internal.Log.setOutput(new PrintStream(noOpOutputStream)); + } + lineReader = null; + } catch (IOException ioe) { + logger.log(Level.WARNING, "Error closing terminal", ioe); } } } diff --git a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/LoginCommand.java b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/LoginCommand.java index 275b906d1b3..5290de0bf34 100644 --- a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/LoginCommand.java +++ b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/LoginCommand.java @@ -44,16 +44,16 @@ import com.sun.appserv.management.client.prefs.LoginInfo; import com.sun.appserv.management.client.prefs.LoginInfoStore; import com.sun.appserv.management.client.prefs.LoginInfoStoreFactory; -import com.sun.enterprise.admin.cli.remote.*; +import com.sun.enterprise.admin.cli.remote.DASUtils; import com.sun.enterprise.universal.i18n.LocalStringsImpl; import com.sun.enterprise.util.SystemPropertyConstants; -import java.io.IOException; -import java.util.logging.Level; - -import jline.console.ConsoleReader; -import org.glassfish.api.admin.*; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandValidationException; import org.glassfish.hk2.api.PerLookup; -import org.jvnet.hk2.annotations.*; +import org.jvnet.hk2.annotations.Service; + +import org.jline.reader.EndOfFileException; +import org.jline.reader.UserInterruptException; /** * The asadmin login command. @@ -122,27 +122,26 @@ protected int executeCommand() throws CommandException, CommandValidationExcepti */ private String getAdminUser() { String user = null; - - try (ConsoleReader console = new ConsoleReader(System.in, System.out, null)) { + try { + buildTerminal(); + buildLineReader(); + String defuser = programOpts.getUser(); if (defuser == null) { defuser = SystemPropertyConstants.DEFAULT_ADMIN_USER; } - if (console != null) { - console.setPrompt(strings.get("AdminUserPrompt", defuser)); - String val = null; - val = console.readLine(); - if (val != null && val.length() > 0){ - user = val; - } else { - user = defuser; - } + String val = lineReader.readLine(strings.get("AdminUserPrompt", defuser)); + if (val != null && val.length() > 0) { + user = val; + } else { + user = defuser; } - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + } finally { + closeTerminal(); } - return user; } diff --git a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/MultimodeCommand.java b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/MultimodeCommand.java index fb1264aeeb0..636604b4d26 100644 --- a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/MultimodeCommand.java +++ b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/MultimodeCommand.java @@ -1,351 +1,380 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at packager/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ -// Portions Copyright [2018] Payara Foundation and/or affiliates - -package com.sun.enterprise.admin.cli; - -import static com.sun.enterprise.admin.cli.CLICommand.ERROR; -import java.io.*; -import java.util.*; - -import org.jvnet.hk2.annotations.Service; -import org.glassfish.api.Param; -import org.glassfish.api.admin.*; -import org.glassfish.api.admin.CommandModel.ParamModel; -import org.glassfish.hk2.api.ActiveDescriptor; -import org.glassfish.hk2.api.DynamicConfiguration; -import org.glassfish.hk2.api.DynamicConfigurationService; -import org.glassfish.hk2.api.PerLookup; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.utilities.BuilderHelper; - -import com.sun.enterprise.admin.util.*; -import com.sun.enterprise.universal.i18n.LocalStringsImpl; -import java.util.logging.Level; - -import javax.inject.Inject; -import jline.console.ConsoleReader; -import jline.console.completer.Completer; -import jline.console.completer.StringsCompleter; - -/** - * A scaled-down implementation of multi-mode command. - * - * @author केदार(km@dev.java.net) - * @author Bill Shannon - */ -@Service(name = "multimode") -@PerLookup -public class MultimodeCommand extends CLICommand { - - @Inject - private ServiceLocator habitat; - @Inject - private CLIContainer container; - @Param(optional = true, shortName = "f") - private File file; - @Param(name = "printprompt", optional = true) - private Boolean printPromptOpt; - private boolean printPrompt; - @Param(optional = true) - private String encoding; - private boolean echo; // saved echo flag - private static final LocalStringsImpl strings = new LocalStringsImpl(MultimodeCommand.class); - - private static final String ASADMIN = "asadmin"; - - /** - * The validate method validates that the type and quantity of parameters - * and operands matches the requirements for this command. The validate - * method supplies missing options from the environment. - * @throws CommandException - * @throws CommandValidationException - */ - @Override - protected void validate() throws CommandException, CommandValidationException { - if (printPromptOpt != null) { - printPrompt = printPromptOpt; - } else { - printPrompt = programOpts.isInteractive(); - } - /* - * Save value of --echo because CLICommand will reset it - * before calling our executeCommand method but we want it - * to also apply to all commands in multimode. - */ - echo = programOpts.isEcho(); - } - - /** - * In the usage message modify the --printprompt option to have a default - * based on the --interactive option. - * @return - */ - @Override - protected Collection usageOptions() { - Collection opts = commandModel.getParameters(); - Set uopts = new LinkedHashSet(); - ParamModel p = new CommandModelData.ParamModelData("printprompt", boolean.class, true, Boolean.toString(programOpts.isInteractive())); - for (ParamModel pm : opts) { - if (pm.getName().equals("printprompt")) { - uopts.add(p); - } else { - uopts.add(pm); - } - } - return uopts; - } - - @Override - protected int executeCommand() throws CommandException, CommandValidationException { - ConsoleReader reader = null; - programOpts.setEcho(echo); // restore echo flag, saved in validate - try { - if (file == null) { - System.out.println(strings.get("multimodeIntro")); - reader = new ConsoleReader(ASADMIN, System.in, System.out, null, encoding); - } else { - printPrompt = false; - if (!file.canRead()) { - throw new CommandException("File: " + file + " can not be read"); - } - OutputStream out = new OutputStream() { - - @Override - public void write(int b) throws IOException { - return; - } - - @Override - public void write(byte[] b) throws IOException { - return; - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - return; - } - }; - reader = new ConsoleReader(ASADMIN, new FileInputStream(file), out, null, encoding); - } - - reader.setBellEnabled(false); - reader.addCompleter(getAllCommandsCompleter()); - - return executeCommands(reader); - } - catch (IOException e) { - throw new CommandException(e); - } - finally { - try { - if (file != null && reader != null) - reader.close(); - } - catch (Exception e) { - // ignore it - } - } - } - - private static void atomicReplace(ServiceLocator locator, ProgramOptions options) { - DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class); - DynamicConfiguration config = dcs.createDynamicConfiguration(); - - config.addUnbindFilter(BuilderHelper.createContractFilter(ProgramOptions.class.getName())); - ActiveDescriptor desc = BuilderHelper.createConstantDescriptor(options, null, ProgramOptions.class); - config.addActiveDescriptor(desc); - - config.commit(); - } - - /** - * Read commands from the specified BufferedReader and execute them. If - * printPrompt is set, prompt first. - * - * @return the exit code of the last command executed - */ - private int executeCommands(ConsoleReader reader) throws CommandException, CommandValidationException, IOException { - String line = null; - int rc = 0; - - /* - * Any program options we start with are copied to the environment - * to serve as defaults for commands we run, and then we give each - * command an empty program options. - */ - programOpts.toEnvironment(env); - String prompt = programOpts.getCommandName() + "> "; - for (;;) { - if (printPrompt) { - line = reader.readLine(prompt); - } else { - line = reader.readLine(); - } - if (line == null) { - if (printPrompt) - System.out.println(); - break; - } - - if (line.trim().startsWith("#")){ // ignore comment lines - continue; - } - - String[] args; - try { - args = getArgs(line); - } catch (ArgumentTokenizer.ArgumentException ex) { - logger.info(ex.getMessage()); - continue; - } - - if (args.length == 0) { - continue; - } - - String command = args[0]; - if (command.length() == 0) { - continue; - } - - // handle built-in exit and quit commands - // XXX - care about their arguments? - if (command.equals("exit") || command.equals("quit")){ - break; - } - - CLICommand cmd = null; - ProgramOptions po = null; - try { - /* - * Every command gets its own copy of program options - * so that any program options specified in its - * command line options don't effect other commands. - * But all commands share the same environment. - */ - po = new ProgramOptions(env); - // copy over AsadminMain info - po.setClassPath(programOpts.getClassPath()); - po.setClassName(programOpts.getClassName()); - po.setCommandName(programOpts.getCommandName()); - // remove the old one and replace it - atomicReplace(habitat, po); - - cmd = CLICommand.getCommand(habitat, command); - rc = cmd.execute(args); - } - catch (CommandValidationException cve) { - logger.severe(cve.getMessage()); - if (cmd != null) { - logger.severe(cmd.getUsage()); - } - rc = ERROR; - } - catch (InvalidCommandException ice) { - // find closest match with local or remote commands - logger.severe(ice.getMessage()); - try { - if(po != null) // many layers below, null WILL be de-referenced. - CLIUtil.displayClosestMatch(command, - CLIUtil.getAllCommands(container, po, env), - strings.get("ClosestMatchedLocalAndRemoteCommands"), logger); - } - catch (InvalidCommandException e) { - // not a big deal if we cannot help - } - rc = ERROR; - } - catch (CommandException ce) { - if (ce.getCause() instanceof java.net.ConnectException) { - // find closest match with local commands - logger.severe(ce.getMessage()); - try { - CLIUtil.displayClosestMatch(command, - CLIUtil.getLocalCommands(container), - strings.get("ClosestMatchedLocalCommands"), logger); - } - catch (InvalidCommandException e) { - logger.info(strings.get("InvalidRemoteCommand", command)); - } - } else { - logger.severe(ce.getMessage()); - } - rc = ERROR; - } finally { - // restore the original program options - // XXX - is this necessary? - atomicReplace(habitat, programOpts); - } - - // XXX - this duplicates code in AsadminMain, refactor it - switch (rc) { - case SUCCESS: - if (!programOpts.isTerse()) - logger.log(Level.FINE, strings.get("CommandSuccessful", command)); - break; - - case ERROR: - case INVALID_COMMAND_ERROR: - case CONNECTION_ERROR: - default: - logger.log(Level.FINE, strings.get("CommandUnSuccessful", command)); - break; - } - CLIUtil.writeCommandToDebugLog(programOpts.getCommandName() + "[multimode]", env, args, rc); - } - return rc; - } - - private String[] getArgs(String line) throws ArgumentTokenizer.ArgumentException { - - List args = new ArrayList(); - ArgumentTokenizer t = new ArgumentTokenizer(line); - while (t.hasMoreTokens()) { - args.add(t.nextToken()); - } - return args.toArray(new String[args.size()]); - } - - private Completer getAllCommandsCompleter(){ - return new StringsCompleter(CLIUtil.getAllCommands(container, programOpts, env)); - - } -} +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +// Portions Copyright [2018-2019] Payara Foundation and/or affiliates + +package com.sun.enterprise.admin.cli; + +import com.sun.enterprise.admin.util.CommandModelData; +import com.sun.enterprise.universal.i18n.LocalStringsImpl; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.*; +import java.util.logging.Level; +import javax.inject.Inject; +import org.glassfish.api.Param; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandModel.ParamModel; +import org.glassfish.api.admin.CommandValidationException; +import org.glassfish.api.admin.InvalidCommandException; +import org.glassfish.hk2.api.*; +import org.glassfish.hk2.utilities.BuilderHelper; +import org.jline.reader.Completer; +import org.jline.reader.EndOfFileException; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.UserInterruptException; +import org.jline.reader.impl.completer.StringsCompleter; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.terminal.impl.ExternalTerminal; +import org.jvnet.hk2.annotations.Service; + +/** + * A scaled-down implementation of multi-mode command. + * + * @author केदार(km@dev.java.net) + * @author Bill Shannon + */ +@Service(name = "multimode") +@PerLookup +public class MultimodeCommand extends CLICommand { + + @Inject + private ServiceLocator habitat; + @Inject + private CLIContainer container; + @Param(optional = true, shortName = "f") + private File file; + @Param(name = "printprompt", optional = true) + private Boolean printPromptOpt; + private boolean printPrompt; + @Param(optional = true) + private String encoding; + private boolean echo; // saved echo flag + private static final LocalStringsImpl strings = new LocalStringsImpl(MultimodeCommand.class); + + /** + * The validate method validates that the type and quantity of parameters + * and operands matches the requirements for this command. The validate + * method supplies missing options from the environment. + * @throws CommandException + * @throws CommandValidationException + */ + @Override + protected void validate() throws CommandException, CommandValidationException { + if (printPromptOpt != null) { + printPrompt = printPromptOpt; + } else { + printPrompt = programOpts.isInteractive(); + } + /* + * Save value of --echo because CLICommand will reset it + * before calling our executeCommand method but we want it + * to also apply to all commands in multimode. + */ + echo = programOpts.isEcho(); + } + + /** + * In the usage message modify the --printprompt option to have a default + * based on the --interactive option. + * @return + */ + @Override + protected Collection usageOptions() { + Collection opts = commandModel.getParameters(); + Set uopts = new LinkedHashSet(); + ParamModel p = new CommandModelData.ParamModelData("printprompt", boolean.class, true, Boolean.toString(programOpts.isInteractive())); + for (ParamModel pm : opts) { + if (pm.getName().equals("printprompt")) { + uopts.add(p); + } else { + uopts.add(pm); + } + } + return uopts; + } + + @Override + protected int executeCommand() throws CommandException, CommandValidationException { + LineReader reader = null; + programOpts.setEcho(echo); // restore echo flag, saved in validate + try { + if (file == null) { + System.out.println(strings.get("multimodeIntro")); + Completer completer = getAllCommandsCompleter(); + Terminal asadminTerminal = TerminalBuilder.builder() + .name(ASADMIN) + .system(true) + .encoding(encoding != null ? Charset.forName(encoding) : Charset.defaultCharset()) + .build(); + + reader = LineReaderBuilder.builder() + .appName(ASADMIN) + .terminal(asadminTerminal) + .completer(completer) + .build(); + + reader.unsetOpt(LineReader.Option.INSERT_TAB); + } else { + + printPrompt = false; + if (!file.canRead()) { + throw new CommandException("File: " + file + " can not be read"); + } + OutputStream out = new OutputStream() { + + @Override + public void write(int b) throws IOException { + return; + } + + @Override + public void write(byte[] b) throws IOException { + return; + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + return; + } + }; + + Terminal asadminTerminal = new ExternalTerminal(ASADMIN, "", + new FileInputStream(file), out, encoding != null ? Charset.forName(encoding) : Charset.defaultCharset()); + + reader = LineReaderBuilder.builder() + .terminal(asadminTerminal) + .appName(ASADMIN) + .build(); + } + + return executeCommands(reader); + } catch (IOException e) { + throw new CommandException(e); + } finally { + try { + if (file != null && reader != null && reader.getTerminal() != null) { + reader.getTerminal().close(); + } + } catch (Exception e) { + // ignore it + } + } + } + + private static void atomicReplace(ServiceLocator locator, ProgramOptions options) { + DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class); + DynamicConfiguration config = dcs.createDynamicConfiguration(); + + config.addUnbindFilter(BuilderHelper.createContractFilter(ProgramOptions.class.getName())); + ActiveDescriptor desc = BuilderHelper.createConstantDescriptor(options, null, ProgramOptions.class); + config.addActiveDescriptor(desc); + + config.commit(); + } + + /** + * Read commands from the specified BufferedReader and execute them. If + * printPrompt is set, prompt first. + * + * @return the exit code of the last command executed + */ + private int executeCommands(LineReader reader) throws IOException { + String line = null; + int rc = 0; + + /* + * Any program options we start with are copied to the environment + * to serve as defaults for commands we run, and then we give each + * command an empty program options. + */ + programOpts.toEnvironment(env); + String prompt = programOpts.getCommandName() + "> "; + for (;;) { + try { + if (printPrompt) { + line = reader.readLine(prompt); + } else { + line = reader.readLine(); + } + if (line == null) { + if (printPrompt) { + System.out.println(); + } + break; + } + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + break; + } + + if (line.trim().startsWith("#")){ // ignore comment lines + continue; + } + + String[] args; + try { + args = getArgs(line); + } catch (ArgumentTokenizer.ArgumentException ex) { + logger.info(ex.getMessage()); + continue; + } + + if (args.length == 0) { + continue; + } + + String command = args[0]; + if (command.length() == 0) { + continue; + } + + // handle built-in exit and quit commands + // XXX - care about their arguments? + if (command.equals("exit") || command.equals("quit")){ + break; + } + + CLICommand cmd = null; + ProgramOptions po = null; + try { + /* + * Every command gets its own copy of program options + * so that any program options specified in its + * command line options don't effect other commands. + * But all commands share the same environment. + */ + po = new ProgramOptions(env); + // copy over AsadminMain info + po.setClassPath(programOpts.getClassPath()); + po.setClassName(programOpts.getClassName()); + po.setCommandName(programOpts.getCommandName()); + // remove the old one and replace it + atomicReplace(habitat, po); + + cmd = CLICommand.getCommand(habitat, command); + + if (file == null) { + rc = cmd.execute(reader.getTerminal(), args); + } else { + rc = cmd.execute(args); + } + } + catch (CommandValidationException cve) { + logger.severe(cve.getMessage()); + if (cmd != null) { + logger.severe(cmd.getUsage()); + } + rc = ERROR; + } + catch (InvalidCommandException ice) { + // find closest match with local or remote commands + logger.severe(ice.getMessage()); + try { + if(po != null) // many layers below, null WILL be de-referenced. + CLIUtil.displayClosestMatch(command, + CLIUtil.getAllCommands(container, po, env), + strings.get("ClosestMatchedLocalAndRemoteCommands"), logger); + } + catch (InvalidCommandException e) { + // not a big deal if we cannot help + } + rc = ERROR; + } + catch (CommandException ce) { + if (ce.getCause() instanceof java.net.ConnectException) { + // find closest match with local commands + logger.severe(ce.getMessage()); + try { + CLIUtil.displayClosestMatch(command, + CLIUtil.getLocalCommands(container), + strings.get("ClosestMatchedLocalCommands"), logger); + } + catch (InvalidCommandException e) { + logger.info(strings.get("InvalidRemoteCommand", command)); + } + } else { + logger.severe(ce.getMessage()); + } + rc = ERROR; + } finally { + // restore the original program options + // XXX - is this necessary? + atomicReplace(habitat, programOpts); + } + + // XXX - this duplicates code in AsadminMain, refactor it + switch (rc) { + case SUCCESS: + if (!programOpts.isTerse()) + logger.log(Level.FINE, strings.get("CommandSuccessful", command)); + break; + + case ERROR: + case INVALID_COMMAND_ERROR: + case CONNECTION_ERROR: + default: + logger.log(Level.FINE, strings.get("CommandUnSuccessful", command)); + break; + } + CLIUtil.writeCommandToDebugLog(programOpts.getCommandName() + "[multimode]", env, args, rc); + } + return rc; + } + + private String[] getArgs(String line) throws ArgumentTokenizer.ArgumentException { + + List args = new ArrayList(); + ArgumentTokenizer t = new ArgumentTokenizer(line); + while (t.hasMoreTokens()) { + args.add(t.nextToken()); + } + return args.toArray(new String[args.size()]); + } + + private Completer getAllCommandsCompleter(){ + return new StringsCompleter(CLIUtil.getAllCommands(container, programOpts, env)); + + } +} diff --git a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCLICommand.java b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCLICommand.java index 8baef9e6136..1194ce89473 100644 --- a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCLICommand.java +++ b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCLICommand.java @@ -61,31 +61,27 @@ import com.sun.enterprise.universal.i18n.LocalStringsImpl; import com.sun.enterprise.util.StringUtils; import com.sun.enterprise.util.SystemPropertyConstants; -import java.io.*; -import java.net.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jline.console.ConsoleReader; import org.glassfish.api.ActionReport; import org.glassfish.api.ActionReport.ExitCode; -import org.glassfish.api.admin.AdminCommandEventBroker; +import org.glassfish.api.admin.*; import org.glassfish.api.admin.AdminCommandEventBroker.AdminCommandListener; -import org.glassfish.api.admin.AdminCommandState; -import org.glassfish.api.admin.CommandException; import org.glassfish.api.admin.CommandModel.ParamModel; -import org.glassfish.api.admin.CommandProgress; -import org.glassfish.api.admin.CommandValidationException; -import org.glassfish.api.admin.ParameterMap; import org.glassfish.common.util.admin.ManPageFinder; import org.glassfish.hk2.api.ActiveDescriptor; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.utilities.BuilderHelper; import org.jvnet.hk2.component.MultiMap; +import java.io.*; +import java.net.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.jline.reader.EndOfFileException; +import org.jline.reader.UserInterruptException; + /** * A remote command handled by the asadmin CLI. */ @@ -172,9 +168,11 @@ public void fetchCommandModel() throws CommandException { * caller should try the request again). */ @Override - protected boolean updateAuthentication() { - try (ConsoleReader console = new ConsoleReader(System.in, System.out, null)) { - if (programOpts.isInteractive() && console != null) { + protected boolean updateAuthentication() { + try { + buildTerminal(); + buildLineReader(); + if (programOpts.isInteractive() && lineReader != null) { // if appropriate, tell the user why authentication failed PasswordLocation pwloc = programOpts.getPasswordLocation(); if (pwloc == PasswordLocation.PASSWORD_FILE) { @@ -183,8 +181,7 @@ protected boolean updateAuthentication() { try { LoginInfoStore store = LoginInfoStoreFactory.getDefaultStore(); logger.log(Level.FINE, strings.get("BadPasswordFromLogin", store.getName())); - } - catch (StoreException ex) { + } catch (StoreException ex) { // ignore it } } @@ -195,13 +192,8 @@ protected boolean updateAuthentication() { // correct username to begin with and all we need is the // password. if (programOpts.getUser() == null) { - console.setPrompt(strings.get("AdminUserPrompt")); - try { - user = console.readLine(); - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); - } + user = lineReader.readLine(strings.get("AdminUserPrompt")); if (user == null) { return false; @@ -214,7 +206,7 @@ protected boolean updateAuthentication() { } else { password = readPassword(strings.get("AdminPasswordPrompt")); } - if (password == null){ + if (password == null) { return false; } if (ok(user)) { // if none entered, don't change @@ -225,10 +217,11 @@ protected boolean updateAuthentication() { this.password = password; return true; } - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + } finally { + closeTerminal(); } - return false; } diff --git a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCommand.java b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCommand.java index 65891816811..30a339509e6 100644 --- a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCommand.java +++ b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCommand.java @@ -45,28 +45,39 @@ import com.sun.appserv.management.client.prefs.LoginInfoStore; import com.sun.appserv.management.client.prefs.LoginInfoStoreFactory; import com.sun.appserv.management.client.prefs.StoreException; -import com.sun.enterprise.admin.cli.*; +import com.sun.enterprise.admin.cli.CLICommand; +import com.sun.enterprise.admin.cli.DirectoryClassLoader; +import com.sun.enterprise.admin.cli.Environment; +import com.sun.enterprise.admin.cli.ProgramOptions; import com.sun.enterprise.admin.cli.ProgramOptions.PasswordLocation; import com.sun.enterprise.admin.remote.RemoteAdminCommand; -import com.sun.enterprise.admin.util.*; +import com.sun.enterprise.admin.util.CachedCommandModel; +import com.sun.enterprise.admin.util.CommandModelData; import com.sun.enterprise.admin.util.CommandModelData.ParamModelData; -import com.sun.enterprise.module.*; +import com.sun.enterprise.module.ModulesRegistry; import com.sun.enterprise.module.single.StaticModulesRegistry; import com.sun.enterprise.security.store.AsadminSecurityUtil; import com.sun.enterprise.universal.i18n.LocalStringsImpl; import com.sun.enterprise.util.SystemPropertyConstants; -import java.io.*; -import java.net.*; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jline.console.ConsoleReader; -import org.glassfish.api.admin.*; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandModel; +import org.glassfish.api.admin.CommandValidationException; +import org.glassfish.api.admin.ParameterMap; import org.glassfish.common.util.admin.ManPageFinder; import org.glassfish.hk2.api.ActiveDescriptor; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.utilities.BuilderHelper; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.terminal.impl.DumbTerminal; + +import java.io.*; +import java.net.*; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; /** * A remote command handled by the asadmin CLI. @@ -135,8 +146,14 @@ public void fetchCommandModel() throws CommandException { */ @Override protected boolean updateAuthentication() { - try (ConsoleReader console = new ConsoleReader(System.in, System.out, null)) { - if (programOpts.isInteractive() && console != null) { + + LineReader lineReader = null; + try { + lineReader = LineReaderBuilder.builder() + .terminal(new DumbTerminal(System.in, System.out)) + .build(); + + if (programOpts.isInteractive() && lineReader != null) { // if appropriate, tell the user why authentication failed PasswordLocation pwloc = programOpts.getPasswordLocation(); if (pwloc == PasswordLocation.PASSWORD_FILE) { @@ -156,13 +173,7 @@ protected boolean updateAuthentication() { // correct username to begin with and all we need is the // password. if (programOpts.getUser() == null) { - console.setPrompt(strings.get("AdminUserPrompt")); - - try { - user = console.readLine(); - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); - } + user = lineReader.readLine(strings.get("AdminUserPrompt")); if (user == null) return false; @@ -188,6 +199,15 @@ protected boolean updateAuthentication() { } catch (IOException ioe) { logger.log(Level.WARNING, "Error reading input", ioe); } + finally { + if (lineReader != null && lineReader.getTerminal() != null) { + try { + lineReader.getTerminal().close(); + } catch (IOException ioe) { + logger.log(Level.WARNING, "Error closing terminal", ioe); + } + } + } return false; } diff --git a/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/ChangeAdminPasswordCommand.java b/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/ChangeAdminPasswordCommand.java index 4050657bde2..d33768d82a9 100644 --- a/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/ChangeAdminPasswordCommand.java +++ b/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/ChangeAdminPasswordCommand.java @@ -37,25 +37,10 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2018] [Payara Foundation and/or its affiliates] +// Portions Copyright [2018-2019] [Payara Foundation and/or its affiliates] package com.sun.enterprise.admin.servermgmt.cli; -import java.io.IOException; -import java.net.ConnectException; -import java.util.logging.Level; - -import jline.console.ConsoleReader; -import org.glassfish.api.I18n; -import org.glassfish.api.Param; -import org.glassfish.api.admin.CommandException; -import org.glassfish.api.admin.CommandValidationException; -import org.glassfish.api.admin.ParameterMap; -import org.glassfish.api.admin.RuntimeType; -import org.glassfish.hk2.api.PerLookup; -import org.glassfish.security.common.FileRealmStorageManager; -import org.jvnet.hk2.annotations.Service; - import com.sun.enterprise.admin.cli.ProgramOptions; import com.sun.enterprise.admin.launcher.GFLauncher; import com.sun.enterprise.admin.launcher.GFLauncherException; @@ -66,6 +51,20 @@ import com.sun.enterprise.universal.xml.MiniXmlParserException; import com.sun.enterprise.util.SystemPropertyConstants; import com.sun.enterprise.util.net.NetUtils; +import org.glassfish.api.I18n; +import org.glassfish.api.Param; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandValidationException; +import org.glassfish.api.admin.ParameterMap; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.hk2.api.PerLookup; +import org.glassfish.security.common.FileRealmStorageManager; +import org.jvnet.hk2.annotations.Service; + +import java.io.IOException; +import java.net.ConnectException; +import org.jline.reader.EndOfFileException; +import org.jline.reader.UserInterruptException; /** * The change-admin-password command. The remote command implementation presents a different interface (set of options) @@ -114,26 +113,24 @@ protected void validate() throws CommandException, CommandValidationException { if (programOpts.getUser() == null) { // prompt for it (if interactive) - try (ConsoleReader cons = new ConsoleReader(System.in, System.out, null)) { - if (cons != null && programOpts.isInteractive()) { - cons.setPrompt(STRINGS.get("AdminUserDefaultPrompt", + try { + buildTerminal(); + buildLineReader(); + if (lineReader != null && programOpts.isInteractive()) { + String val = lineReader.readLine(STRINGS.get("AdminUserDefaultPrompt", SystemPropertyConstants.DEFAULT_ADMIN_USER)); - - try { - String val = cons.readLine(); - if (ok(val)) { - programOpts.setUser(val); - } else { - programOpts.setUser(SystemPropertyConstants.DEFAULT_ADMIN_USER); - } - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); + if (ok(val)) { + programOpts.setUser(val); + } else { + programOpts.setUser(SystemPropertyConstants.DEFAULT_ADMIN_USER); } } else { throw new CommandValidationException(STRINGS.get("AdminUserRequired")); } - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error instantiating console", ioe); + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + } finally { + closeTerminal(); } } diff --git a/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/CreateDomainCommand.java b/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/CreateDomainCommand.java index db4754da289..13f812467ed 100644 --- a/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/CreateDomainCommand.java +++ b/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/CreateDomainCommand.java @@ -41,62 +41,13 @@ package com.sun.enterprise.admin.servermgmt.cli; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.KEYTOOLOPTIONS; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.K_ADMIN_CERT_DN; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.K_ADMIN_PORT; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.K_INITIAL_ADMIN_USER_GROUPS; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.K_INSTANCE_CERT_DN; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.K_PORTBASE; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.K_SECURE_ADMIN_IDENTIFIER; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.K_TEMPLATE_NAME; -import static com.sun.enterprise.admin.servermgmt.DomainConfig.K_VALIDATE_PORTS; -import static com.sun.enterprise.config.util.PortConstants.DEFAULT_INSTANCE_PORT; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_ADMINPORT_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_DEBUG_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_HTTPSSL_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_IIOPMUTUALAUTH_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_IIOPSSL_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_IIOP_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_INSTANCE_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_JMS_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_JMX_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORTBASE_OSGI_SUFFIX; -import static com.sun.enterprise.config.util.PortConstants.PORT_MAX_VAL; -import static com.sun.enterprise.util.SystemPropertyConstants.DEFAULT_ADMIN_PASSWORD; -import static com.sun.enterprise.util.SystemPropertyConstants.DEFAULT_ADMIN_USER; -import static com.sun.enterprise.util.net.NetUtils.checkPort; -import static com.sun.enterprise.util.net.NetUtils.isPortValid; -import static java.util.logging.Level.FINER; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Properties; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; - -import jline.console.ConsoleReader; -import org.glassfish.api.Param; -import org.glassfish.api.admin.CommandException; -import org.glassfish.api.admin.CommandModel.ParamModel; -import org.glassfish.api.admin.CommandValidationException; -import org.glassfish.hk2.api.PerLookup; -import org.glassfish.security.common.FileRealmStorageManager; -import org.jvnet.hk2.annotations.Service; - import com.sun.appserv.management.client.prefs.LoginInfo; import com.sun.appserv.management.client.prefs.LoginInfoStore; import com.sun.appserv.management.client.prefs.LoginInfoStoreFactory; import com.sun.appserv.server.util.Version; import com.sun.enterprise.admin.cli.CLICommand; import com.sun.enterprise.admin.cli.CLIConstants; -import com.sun.enterprise.admin.servermgmt.DomainConfig; -import com.sun.enterprise.admin.servermgmt.DomainException; -import com.sun.enterprise.admin.servermgmt.DomainsManager; -import com.sun.enterprise.admin.servermgmt.KeystoreManager; -import com.sun.enterprise.admin.servermgmt.RepositoryManager; +import com.sun.enterprise.admin.servermgmt.*; import com.sun.enterprise.admin.servermgmt.domain.DomainBuilder; import com.sun.enterprise.admin.servermgmt.pe.PEDomainsManager; import com.sun.enterprise.admin.util.CommandModelData.ParamModelData; @@ -104,6 +55,26 @@ import com.sun.enterprise.util.SystemPropertyConstants; import com.sun.enterprise.util.io.FileUtils; import com.sun.enterprise.util.net.NetUtils; +import org.glassfish.api.Param; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandModel.ParamModel; +import org.glassfish.api.admin.CommandValidationException; +import org.glassfish.hk2.api.PerLookup; +import org.glassfish.security.common.FileRealmStorageManager; +import org.jvnet.hk2.annotations.Service; + +import java.io.File; +import java.util.*; + +import static com.sun.enterprise.admin.servermgmt.DomainConfig.*; +import static com.sun.enterprise.config.util.PortConstants.*; +import static com.sun.enterprise.util.SystemPropertyConstants.DEFAULT_ADMIN_PASSWORD; +import static com.sun.enterprise.util.SystemPropertyConstants.DEFAULT_ADMIN_USER; +import static com.sun.enterprise.util.net.NetUtils.checkPort; +import static com.sun.enterprise.util.net.NetUtils.isPortValid; +import static java.util.logging.Level.FINER; +import org.jline.reader.EndOfFileException; +import org.jline.reader.UserInterruptException; /** * This is a local command that creates a domain. @@ -224,11 +195,12 @@ protected void validate() throws CommandException, CommandValidationException { */ if (programOpts.getUser() == null && !noPassword) { // prompt for it (if interactive) - try (ConsoleReader console = new ConsoleReader(System.in, System.out, null)) { - if (console != null && programOpts.isInteractive()) { - console.setPrompt(STRINGS.get("AdminUserRequiredPrompt", SystemPropertyConstants.DEFAULT_ADMIN_USER)); - String val = console.readLine(); + try { + buildTerminal(); + buildLineReader(); + if (lineReader != null && programOpts.isInteractive()) { + String val = lineReader.readLine(STRINGS.get("AdminUserRequiredPrompt", SystemPropertyConstants.DEFAULT_ADMIN_USER)); if (ok(val)) { programOpts.setUser(val); @@ -240,8 +212,10 @@ protected void validate() throws CommandException, CommandValidationException { } else { throw new CommandValidationException(STRINGS.get("AdminUserRequired")); } - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + } finally { + closeTerminal(); } } diff --git a/nucleus/admin/util/pom.xml b/nucleus/admin/util/pom.xml index 8a428578027..442d9982d4d 100755 --- a/nucleus/admin/util/pom.xml +++ b/nucleus/admin/util/pom.xml @@ -162,8 +162,9 @@ ${jsonp.version} - jline + org.jline jline + ${jline.version} true diff --git a/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/AsadminTrustManager.java b/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/AsadminTrustManager.java index 7e1c13e1ee2..f6f1c32c28c 100644 --- a/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/AsadminTrustManager.java +++ b/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/AsadminTrustManager.java @@ -43,6 +43,11 @@ import com.sun.enterprise.security.store.AsadminTruststore; import com.sun.enterprise.universal.i18n.LocalStringsImpl; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.terminal.impl.DumbTerminal; + +import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -51,8 +56,6 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import javax.net.ssl.X509TrustManager; -import jline.console.ConsoleReader; /** * An implementation of {@link X509TrustManager} that provides basic support @@ -166,19 +169,30 @@ public X509Certificate[] getAcceptedIssuers() { * @return true if the user trusts the certificate */ private boolean isItOKToAddCertToTrustStore(X509Certificate c) { - String result = null; + if (!interactive) { + return true; + } - try (ConsoleReader console = new ConsoleReader(System.in, System.out, null)) { - if (!interactive || console == null) { - return true; - } + String result = null; + LineReader lineReader = null; + try { + lineReader = LineReaderBuilder.builder() + .terminal(new DumbTerminal(System.in, System.out)) + .build(); - console.setPrompt(c.toString()); - result = console.readLine(STRING_MANAGER.get("certificateTrustPrompt")); + result = lineReader.readLine(STRING_MANAGER.get("certificateTrustPrompt")); } catch (IOException ioe) { logger.log(Level.WARNING, "Error instantiating console", ioe); } - + finally { + if (lineReader != null && lineReader.getTerminal() != null) { + try { + lineReader.getTerminal().close(); + } catch (IOException ioe) { + logger.log(Level.WARNING, "Error closing terminal", ioe); + } + } + } return result != null && result.equalsIgnoreCase("y"); } diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalInstanceCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalInstanceCommand.java index 83662777765..ce5b611c0c2 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalInstanceCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalInstanceCommand.java @@ -42,25 +42,25 @@ package com.sun.enterprise.admin.cli.cluster; import com.sun.enterprise.admin.cli.remote.RemoteCLICommand; +import com.sun.enterprise.admin.servermgmt.cli.LocalServerCommand; +import com.sun.enterprise.universal.io.SmartFile; import com.sun.enterprise.util.StringUtils; +import com.sun.enterprise.util.SystemPropertyConstants; import com.sun.enterprise.util.io.FileUtils; import com.sun.enterprise.util.io.InstanceDirs; +import com.sun.enterprise.util.io.ServerDirs; +import com.sun.enterprise.util.net.NetUtils; +import org.glassfish.api.Param; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandValidationException; + import java.io.*; -import java.io.File; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.*; +import java.util.Properties; import java.util.logging.Level; - -import jline.console.ConsoleReader; -import org.glassfish.api.Param; -import org.glassfish.api.admin.*; - -import com.sun.enterprise.admin.servermgmt.cli.LocalServerCommand; -import com.sun.enterprise.util.SystemPropertyConstants; -import com.sun.enterprise.util.net.NetUtils; -import com.sun.enterprise.universal.io.SmartFile; -import com.sun.enterprise.util.io.ServerDirs; +import org.jline.reader.EndOfFileException; +import org.jline.reader.UserInterruptException; /** * A base class for local commands that manage a local server instance. @@ -511,20 +511,23 @@ private int updateDasPort(Properties dasprops, int port, File propfile) { Integer.toString(programOpts.getPort()))); port = programOpts.getPort(); } else { - try (ConsoleReader console = new ConsoleReader(System.in, System.out, null)) { - if (console != null) { - String line = console.readLine(Strings.get("Instance.oldDasPropertiesPrompt", + try { + buildTerminal(); + buildLineReader(); + if (lineReader != null) { + String line = lineReader.readLine(Strings.get("Instance.oldDasPropertiesPrompt", propfile.toString(), Integer.toString(port), Integer.toString(programOpts.getPort()))); while (line != null && line.length() > 0) { try { port = Integer.parseInt(line); - if (port > 0 && port <= 65535) + if (port > 0 && port <= 65535) { break; + } } catch (NumberFormatException nfex) { //try again } - line = console.readLine(Strings.get("Instance.reenterPort", Integer.toString(programOpts.getPort()))); + line = lineReader.readLine(Strings.get("Instance.reenterPort", Integer.toString(programOpts.getPort()))); } } else { logger.info(Strings.get("Instance.oldDasPropertiesWrong", @@ -532,12 +535,10 @@ private int updateDasPort(Properties dasprops, int port, File propfile) { Integer.toString(programOpts.getPort()))); port = programOpts.getPort(); } - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); - logger.info(Strings.get("Instance.oldDasPropertiesWrong", - propfile.toString(), Integer.toString(port), - Integer.toString(programOpts.getPort()))); - port = programOpts.getPort(); + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + } finally { + closeTerminal(); } } diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/SetupLocalDcom.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/SetupLocalDcom.java index c4ae2161074..1b026903a9e 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/SetupLocalDcom.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/SetupLocalDcom.java @@ -41,24 +41,25 @@ package com.sun.enterprise.admin.cli.cluster; -import java.util.logging.Level; +import com.sun.enterprise.admin.cli.CLICommand; import com.sun.enterprise.universal.process.ProcessManager; import com.sun.enterprise.universal.process.ProcessManagerException; -import java.io.*; -import java.util.*; - -import jline.console.ConsoleReader; +import com.sun.enterprise.util.OS; +import com.sun.enterprise.util.io.FileUtils; import org.glassfish.api.Param; -import static com.sun.enterprise.universal.process.ProcessUtils.getExe; - - -import org.jvnet.hk2.annotations.Service; -import org.glassfish.api.admin.*; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandValidationException; import org.glassfish.hk2.api.PerLookup; +import org.jvnet.hk2.annotations.Service; -import com.sun.enterprise.admin.cli.*; -import com.sun.enterprise.util.OS; -import com.sun.enterprise.util.io.FileUtils; +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +import static com.sun.enterprise.universal.process.ProcessUtils.getExe; +import org.jline.reader.EndOfFileException; +import org.jline.reader.UserInterruptException; /* * @author Byron Nevins @@ -77,7 +78,6 @@ public final class SetupLocalDcom extends CLICommand { private static final String CPP_APP_FILENAME = "DcomConfigurator.exe"; private static final File TMPDIR = new File(System.getProperty("java.io.tmpdir")); private static final File CPP_APP = new File(TMPDIR, CPP_APP_FILENAME); - private ConsoleReader console; @Override protected void validate() throws CommandException { @@ -86,18 +86,16 @@ protected void validate() throws CommandException { if (!OS.isWindowsForSure()) throw new CommandException(Strings.get("vld.windows.only")); - // Instantiate console if null - if (console == null) { - try { - console = new ConsoleReader(System.in, System.out, null); - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error instantiating console", ioe); - } - } + try { + buildTerminal(); + buildLineReader(); - // Check if console is still null - if (console == null) { - throw new CommandException(Strings.get("vld.noconsole")); + // Check if console is still null + if (lineReader == null) { + throw new CommandException(Strings.get("vld.noconsole")); + } + } finally { + closeTerminal(); } if(!force) @@ -221,11 +219,11 @@ private static void copyStream(InputStream in, OutputStream out) throws IOExcept out.write(buf, 0, len); } } + /* * note how this method will likely be inlined by the compiler since it is tiny * and private... */ - private CommandException exceptionMaker(String key, Object... args) { if (args == null || args.length == 0) return new CommandException(Strings.get(key)); @@ -234,19 +232,17 @@ private CommandException exceptionMaker(String key, Object... args) { } private void areYouSure() throws CommandException { - if (!programOpts.isInteractive()) + if (!programOpts.isInteractive()) { throw new CommandException(Strings.get("vld.not.interactive")); - - String msg = Strings.get("vld.areyousure"); - - String answer = null; + } + try { - answer = console.readLine(msg); - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); + String answer = lineReader.readLine(String.format("%s: ", Strings.get("vld.areyousure"))); + if (!"yes".equalsIgnoreCase(answer)) { + throw new CommandException(Strings.get("vld.no")); + } + } catch (UserInterruptException | EndOfFileException e) { + // Ignore } - - if (!"yes".equalsIgnoreCase(answer)) - throw new CommandException(Strings.get("vld.no")); } } diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/SetupSshKey.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/SetupSshKey.java index 25e1c4a27e4..368cd4bb35f 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/SetupSshKey.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/SetupSshKey.java @@ -41,22 +41,26 @@ package com.sun.enterprise.admin.cli.cluster; -import java.io.*; -import java.util.Arrays; -import java.util.logging.Level; - -import javax.inject.Inject; - - -import jline.console.ConsoleReader; -import org.jvnet.hk2.annotations.Service; import org.glassfish.api.Param; -import org.glassfish.api.admin.*; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.cluster.ssh.launcher.SSHLauncher; +import org.glassfish.cluster.ssh.util.SSHUtil; import org.glassfish.hk2.api.PerLookup; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.internal.api.Globals; -import org.glassfish.cluster.ssh.launcher.SSHLauncher; -import org.glassfish.cluster.ssh.util.SSHUtil; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.terminal.impl.DumbTerminal; +import org.jvnet.hk2.annotations.Service; + +import javax.inject.Inject; +import java.io.IOException; +import java.util.Arrays; +import java.util.logging.Level; +import org.jline.reader.EndOfFileException; +import org.jline.reader.UserInterruptException; /** * This is a local command that distributes the SSH public key to remote node(s) @@ -172,12 +176,13 @@ private boolean promptForKeyGeneration() { if (!programOpts.isInteractive()) return false; - try (ConsoleReader console = new ConsoleReader(System.in, System.out, null)) { - if (console != null) { - String val = null; + try { + buildTerminal(); + buildLineReader(); + if (lineReader != null) { + String val; do { - console.setPrompt(Strings.get("GenerateKeyPairPrompt", getRemoteUser(), Arrays.toString(hosts))); - val = console.readLine(); + val = lineReader.readLine(Strings.get("GenerateKeyPairPrompt", getRemoteUser(), Arrays.toString(hosts))); if (val != null && (val.equalsIgnoreCase("yes") || val.equalsIgnoreCase("y"))) { if (logger.isLoggable(Level.FINER)) { logger.finer("Generate key!"); @@ -188,9 +193,12 @@ private boolean promptForKeyGeneration() { } } while (val != null && !isValidAnswer(val)); } - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error reading input", ioe); + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + } finally { + closeTerminal(); } + return false; } diff --git a/nucleus/common/common-util/pom.xml b/nucleus/common/common-util/pom.xml index 91437da734f..8de1997e7d8 100755 --- a/nucleus/common/common-util/pom.xml +++ b/nucleus/common/common-util/pom.xml @@ -40,7 +40,7 @@ holder. --> - + @@ -123,8 +123,9 @@ provided - jline + org.jline jline + ${jline.version} true diff --git a/nucleus/common/common-util/src/main/java/com/sun/enterprise/security/store/AsadminSecurityUtil.java b/nucleus/common/common-util/src/main/java/com/sun/enterprise/security/store/AsadminSecurityUtil.java index 16a1539d372..cc7f122927c 100644 --- a/nucleus/common/common-util/src/main/java/com/sun/enterprise/security/store/AsadminSecurityUtil.java +++ b/nucleus/common/common-util/src/main/java/com/sun/enterprise/security/store/AsadminSecurityUtil.java @@ -38,14 +38,13 @@ * holder. */ // Portions Copyright [2018-2019] [Payara Foundation and/or its affiliates] + package com.sun.enterprise.security.store; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; +import com.sun.enterprise.universal.i18n.LocalStringsImpl; +import com.sun.enterprise.util.CULoggerInfo; +import com.sun.enterprise.util.SystemPropertyConstants; +import java.io.*; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -53,12 +52,12 @@ import java.security.cert.CertificateException; import java.util.logging.Level; import java.util.logging.Logger; - -import jline.console.ConsoleReader; - -import com.sun.enterprise.universal.i18n.LocalStringsImpl; -import com.sun.enterprise.util.CULoggerInfo; -import com.sun.enterprise.util.SystemPropertyConstants; +import org.jline.reader.EndOfFileException; +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; /** * Various utility methods related to certificate-based security. @@ -173,18 +172,30 @@ private AsadminSecurityUtil(final char[] commandLineMasterPassword, final boolea * the password by calling this method. * @return the password to the client side truststore */ - private char[] promptForPassword() throws IOException { - try (ConsoleReader console = new ConsoleReader(System.in, System.out, null)) { - if (console != null) { - // Don't echo anything when reading - char echoCharacter = 0; - console.setEchoCharacter(echoCharacter); - - String line = console.readLine(strmgr.get("certificateDbPrompt")); - return line.toCharArray(); - } + private char[] promptForPassword() { + LineReader lineReader = null; + try { + char mask = 0; + Terminal terminal = TerminalBuilder.builder() + .system(true) + .build(); + lineReader = LineReaderBuilder.builder() + .terminal(terminal).build(); + + String line = lineReader.readLine(strmgr.get("certificateDbPrompt"), mask); + return line.toCharArray(); } catch (IOException ioe) { logger.log(Level.WARNING, "Error reading input", ioe); + } catch (UserInterruptException | EndOfFileException e) { + // Ignore + }finally { + if (lineReader != null && lineReader.getTerminal() != null) { + try { + lineReader.getTerminal().close(); + } catch (IOException ioe) { + logger.log(Level.WARNING, "Error closing terminal", ioe); + } + } } return null; diff --git a/nucleus/osgi-platforms/osgi-cli-interactive/pom.xml b/nucleus/osgi-platforms/osgi-cli-interactive/pom.xml index 70b0da797fd..e8c38631787 100644 --- a/nucleus/osgi-platforms/osgi-cli-interactive/pom.xml +++ b/nucleus/osgi-platforms/osgi-cli-interactive/pom.xml @@ -39,8 +39,8 @@ only if the new code is made subject to such option by the copyright holder. - Portions Copyright [2019] [Payara Foundation and/or its affiliates] --> + 4.0.0 @@ -77,7 +77,7 @@ ${project.version} - jline + org.jline jline diff --git a/nucleus/osgi-platforms/osgi-cli-interactive/src/main/java/org/glassfish/osgi/cli/interactive/LocalOSGiShellCommand.java b/nucleus/osgi-platforms/osgi-cli-interactive/src/main/java/org/glassfish/osgi/cli/interactive/LocalOSGiShellCommand.java index c36cc1be539..605c603204e 100644 --- a/nucleus/osgi-platforms/osgi-cli-interactive/src/main/java/org/glassfish/osgi/cli/interactive/LocalOSGiShellCommand.java +++ b/nucleus/osgi-platforms/osgi-cli-interactive/src/main/java/org/glassfish/osgi/cli/interactive/LocalOSGiShellCommand.java @@ -41,42 +41,33 @@ package org.glassfish.osgi.cli.interactive; -import com.sun.enterprise.admin.cli.ArgumentTokenizer; -import com.sun.enterprise.admin.cli.CLICommand; -import com.sun.enterprise.admin.cli.CLIUtil; -import com.sun.enterprise.admin.cli.Environment; -import com.sun.enterprise.admin.cli.MultimodeCommand; -import com.sun.enterprise.admin.cli.ProgramOptions; +import com.sun.enterprise.admin.cli.*; import com.sun.enterprise.admin.cli.remote.RemoteCLICommand; import com.sun.enterprise.admin.util.CommandModelData; import com.sun.enterprise.universal.i18n.LocalStringsImpl; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import java.io.*; +import java.nio.charset.Charset; +import java.util.*; +import java.util.logging.Level; import javax.inject.Inject; -import jline.console.ConsoleReader; -import jline.console.completer.Completer; -import jline.console.completer.NullCompleter; -import jline.console.completer.StringsCompleter; import org.glassfish.api.I18n; import org.glassfish.api.Param; import org.glassfish.api.admin.CommandException; import org.glassfish.api.admin.CommandModel.ParamModel; import org.glassfish.api.admin.CommandValidationException; import org.glassfish.api.admin.InvalidCommandException; -import org.glassfish.hk2.api.ActiveDescriptor; -import org.glassfish.hk2.api.DynamicConfiguration; -import org.glassfish.hk2.api.DynamicConfigurationService; -import org.glassfish.hk2.api.PerLookup; -import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.hk2.api.*; import org.glassfish.hk2.utilities.BuilderHelper; +import org.jline.reader.Completer; +import org.jline.reader.EndOfFileException; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.UserInterruptException; +import org.jline.reader.impl.completer.NullCompleter; +import org.jline.reader.impl.completer.StringsCompleter; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.jline.terminal.impl.ExternalTerminal; import org.jvnet.hk2.annotations.Service; /** @@ -249,10 +240,13 @@ protected Collection usageOptions() { @Override protected int executeCommand() throws CommandException, CommandValidationException { - if(cmd == null) { + + LineReader reader = null; + + if (cmd == null) { throw new CommandException("Remote command 'osgi' is not available."); } - + programOpts.setEcho(echo); // restore echo flag, saved in validate try { if (encoding != null) { @@ -260,32 +254,60 @@ protected int executeCommand() System.setProperty("input.encoding", encoding); } - String[] args = new String[] {REMOTE_COMMAND, + String[] args = new String[]{REMOTE_COMMAND, "asadmin-osgi-shell"}; args = enhanceForTarget(args); shellType = cmd.executeAndReturnOutput(args).trim(); if (file == null) { + if (terminal != null) { + //Pause the asadmin terminal + terminal.pause(); + } System.out.println(strings.get("multimodeIntro")); - ConsoleReader reader = new ConsoleReader(REMOTE_COMMAND, - new FileInputStream(FileDescriptor.in), System.out, - null); - reader.setBellEnabled(false); - reader.addCompleter(getCommandCompleter()); - return executeCommands(reader); // NB: wrapper on general in/out stream does not need closing by try-with-resource + Terminal osgiShellTerminal = TerminalBuilder.builder() + .name(REMOTE_COMMAND) + .system(true) + .streams(new FileInputStream(FileDescriptor.in), System.out) + .build(); + + reader = LineReaderBuilder.builder() + .appName(REMOTE_COMMAND) + .terminal(osgiShellTerminal) + .completer(getCommandCompleter()) + .build(); + + reader.unsetOpt(LineReader.Option.INSERT_TAB); + return executeCommands(reader); } + printPrompt = false; if (!file.canRead()) { - throw new CommandException("File: " + file + " can not be read"); + throw new CommandException("File: " + file + + " can not be read"); } - try (ConsoleReader reader = new ConsoleReader(REMOTE_COMMAND, new FileInputStream(file), - new NullOutputStream(), null)) { - reader.setBellEnabled(false); - reader.addCompleter(getCommandCompleter()); - return executeCommands(reader); + + try (Terminal osgiShellTerminal = new ExternalTerminal(REMOTE_COMMAND, "", + new FileInputStream(file), new NullOutputStream(), encoding != null ? Charset.forName(encoding) : Charset.defaultCharset())) { + + reader = LineReaderBuilder.builder() + .terminal(osgiShellTerminal) + .appName(REMOTE_COMMAND) + .build(); + + return executeCommands(reader); // NB: wrapper on general in/out stream does not need closing by try-with-resource } + } catch (IOException e) { throw new CommandException(e); + } finally { + if (reader != null && reader.getTerminal() != null) { + try { + reader.getTerminal().close(); + } catch (IOException ioe) { + logger.log(Level.WARNING, "Error closing OSFI Shell terminal", ioe); + } + } } } @@ -376,7 +398,7 @@ private Completer getCommandCompleter() { * * @return the exit code of the last command executed */ - private int executeCommands(ConsoleReader reader) + private int executeCommands(LineReader reader) throws CommandException, CommandValidationException, IOException { String line = null; int rc = 0; @@ -392,19 +414,24 @@ private int executeCommands(ConsoleReader reader) try { for (;;) { - if (printPrompt) { - line = reader.readLine(shellType + "$ "); - } else { - line = reader.readLine(); - } - - if (line == null) { + try { if (printPrompt) { - System.out.println(); + line = reader.readLine(shellType + "$ "); + } else { + line = reader.readLine(); + } + + if (line == null) { + if (printPrompt) { + System.out.println(); + } + break; } + } catch (UserInterruptException | EndOfFileException e) { + // Ignore break; } - + if (line.trim().startsWith("#")) // ignore comment lines { continue; @@ -430,6 +457,9 @@ private int executeCommands(ConsoleReader reader) // handle built-in exit and quit commands // XXX - care about their arguments? if (command.equals("exit") || command.equals("quit")) { + if (terminal != null && terminal.paused()) { + terminal.resume(); + } break; } diff --git a/nucleus/packager/nucleus/pom.xml b/nucleus/packager/nucleus/pom.xml index 4d5f7552827..f185b1c40c8 100644 --- a/nucleus/packager/nucleus/pom.xml +++ b/nucleus/packager/nucleus/pom.xml @@ -247,7 +247,7 @@ true - jline + org.jline jline true diff --git a/nucleus/pom.xml b/nucleus/pom.xml index 5db5e994124..14871184cd8 100644 --- a/nucleus/pom.xml +++ b/nucleus/pom.xml @@ -326,6 +326,7 @@ 0.31.0 + 3.11.0 6.0.2 @@ -1356,9 +1357,9 @@ Parent is ${project.parent} - jline + org.jline jline - 2.14.6 + ${jline.version} org.fusesource.hawtjni