/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.adminclient;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import jline.ArgumentCompletor;
import jline.Completor;
import jline.ConsoleReader;
import jline.SimpleCompletor;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import org.jboss.adminclient.command.ClientCommand;
import org.jboss.adminclient.command.ConnectCommand;
import org.jboss.adminclient.command.DisconnectCommand;
import org.jboss.adminclient.command.ListComponentsCommand;
import org.jboss.adminclient.command.ListDeploymentsCommand;
import org.jboss.adminclient.command.QuitCommand;
import org.jboss.adminclient.command.ReloadCommand;
import org.jboss.adminclient.command.HelpCommand;
import org.jboss.adminclient.command.LoadCommand;
import org.jboss.adminclient.connection.ProfileServiceConnection;
/**
* @author Ian Springer
*/
public class AdminClientMain
{
private static Class[] COMMAND_CLASSES = new Class[]{
ConnectCommand.class,
DisconnectCommand.class,
HelpCommand.class,
ListComponentsCommand.class,
ListDeploymentsCommand.class,
LoadCommand.class,
QuitCommand.class,
ReloadCommand.class
};
// Use a TreeMap, so the commands will be sorted by name (e.g. for display by the help command).
private static final Map<String, ClientCommand> COMMANDS = new TreeMap<String, ClientCommand>();
static
{
for (Class commandClass : COMMAND_CLASSES)
{
ClientCommand command;
try
{
command = (ClientCommand)commandClass.newInstance();
COMMANDS.put(command.getName(), command);
}
catch (Exception e)
{
throw new IllegalStateException(e);
}
}
}
/**
* This is the thread that is running the input loop; it accepts prompt commands from the user.
*/
private Thread inputLoopThread;
private BufferedReader inputReader;
private ConsoleReader consoleReader;
private boolean stdinInput = true;
private PrintWriter outputWriter;
private ProfileServiceConnection connection;
String host;
Integer port;
String username;
String password;
boolean verbose;
public static void main(String[] args) throws Exception
{
/*Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
try {
new UnixTerminal().restoreTerminal(); }
catch (Exception e) { }
}
}));*/
try
{
// new UnixTerminal().initializeTerminal();
AdminClientMain main = new AdminClientMain();
main.processArguments(args);
main.inputLoop();
}
finally
{
//new UnixTerminal().restoreTerminal();
}
}
public AdminClientMain() throws Exception
{
// this.inputReader = new BufferedReader(new InputStreamReader(System.in));
this.outputWriter = new PrintWriter(System.out, true);
consoleReader = new jline.ConsoleReader();
consoleReader.addCompletor(
new SimpleCompletor(COMMANDS.keySet().toArray(new String[COMMANDS.size()])));
consoleReader.addCompletor(
new ArgumentCompletor(
new Completor[]{
new SimpleCompletor("help"),
new SimpleCompletor(COMMANDS.keySet().toArray(new String[COMMANDS.size()]))}));
consoleReader.setUsePagination(true);
}
public void start()
{
outputWriter = new PrintWriter(System.out);
// inputReader = new BufferedReader(new InputStreamReader(System.in));
}
public String getUserInput(String prompt)
{
String inputString = "";
boolean useDefaultPrompt = (prompt == null);
while ((inputString != null) && (inputString.trim().length() == 0))
{
if (prompt == null)
prompt = isConnected() ? (this.host + ":" + this.port + "> ") : "disconnected> ";
try
{
this.outputWriter.flush();
inputString = this.consoleReader.readLine(prompt);
}
catch (Exception e)
{
inputString = null;
}
}
if (inputString != null)
{
// if we are processing a script, show the input that was just read in
if (!stdinInput)
{
outputWriter.println(inputString);
}
}
else if (!stdinInput)
{
// if we are processing a script, we hit the EOF, so close the input stream
try
{
inputReader.close();
}
catch (IOException e1)
{
}
// if we are not in daemon mode, let's now start processing prompt commands coming in via stdin
// if (!m_daemonMode) {
// inputReader = new BufferedReader(new InputStreamReader(System.in));
// stdinInput = true;
// input_string = "";
// } else {
// inputReader = null;
// }
}
return inputString;
}
public boolean isConnected()
{
return (this.connection != null && this.connection.getConnectionProvider().isConnected());
}
/**
* This enters in an infinite loop. Because this never returns, the current thread never dies and hence the agent
* stays up and running. The user can enter agent commands at the prompt - the commands are sent to the agent as if
* the user is a remote client.
*/
private void inputLoop()
{
// we need to start a new thread and run our loop in it; otherwise, our shutdown hook doesn't work
Runnable loopRunnable = new Runnable()
{
public void run()
{
while (true)
{
// get a command from the user
// if in daemon mode, only get input if reading from an input file; ignore stdin
String cmd;
// if ((m_daemonMode == false) || (stdinInput == false)) {
cmd = getUserInput(null);
// } else {
// cmd = null;
// }
boolean continueRunning = executeCommand(cmd);
// break the input loop if the prompt command told us to exit
// if we are not in daemon mode, this really will end up killing the agent
if (!continueRunning)
break;
}
return;
}
};
// Start the input thread.
inputLoopThread = new Thread(loopRunnable);
inputLoopThread.setName("JBoss AS Admin Client Prompt Input Thread");
inputLoopThread.setDaemon(false);
inputLoopThread.start();
return;
}
private boolean executeCommand(String cmd)
{
boolean continueRunning;
try
{
String[] cmdArgs = parseCommandLine(cmd);
continueRunning = executeCommand(cmdArgs);
}
catch (RuntimeException e)
{
e.printStackTrace(getPrintWriter()); // TODO: handle better
continueRunning = true;
}
return continueRunning;
}
private boolean executeCommand(String[] args)
{
String commandName = args[0];
if (COMMANDS.containsKey(commandName))
{
ClientCommand command = COMMANDS.get(commandName);
if (command.isConnectionRequired() && !isConnected())
{
outputWriter.println("The '" + commandName
+ "' command requires a connection. Please run the 'connect' command first.");
return true;
}
String[] params = new String[args.length - 1];
System.arraycopy(args, 1, params, 0, args.length - 1);
OptionParser optionParser = command.getOptionParser();
optionParser.acceptsAll(asList("h", "?", "help"), "display help");
OptionSet options = optionParser.parse(params);
if (options.has("help"))
{
try
{
optionParser.printHelpOn(this.outputWriter);
}
catch (IOException e)
{
throw new IllegalStateException(e);
}
}
else
{
try
{
return command.execute(this, options);
}
catch (Exception e)
{
getPrintWriter().write("Command failed: " + e.getLocalizedMessage());
e.printStackTrace(getPrintWriter());
}
}
}
else
{
//return COMMANDS.get("exec").execute(this, args);
outputWriter.println("Unknown command: " + commandName);
}
return true;
}
/**
* Given a command line, this will parse each argument and return the argument array.
*
* @param cmdLine the command line
* @return the array of command line arguments
*/
private String[] parseCommandLine(String cmdLine)
{
ByteArrayInputStream in = new ByteArrayInputStream(cmdLine.getBytes());
StreamTokenizer strtok = new StreamTokenizer(new InputStreamReader(in));
List<String> args = new ArrayList<String>();
boolean keepGoing = true;
// we don't want to parse numbers and we want ' to be a normal word character
strtok.ordinaryChars('0', '9');
strtok.ordinaryChar('.');
strtok.ordinaryChar('-');
strtok.ordinaryChar('\'');
strtok.wordChars(33, 127);
strtok.quoteChar('\"');
// parse the command line
while (keepGoing)
{
int nextToken;
try
{
nextToken = strtok.nextToken();
}
catch (IOException e)
{
nextToken = StreamTokenizer.TT_EOF;
}
if (nextToken == java.io.StreamTokenizer.TT_WORD)
{
args.add(strtok.sval);
}
else if (nextToken == '\"')
{
args.add(strtok.sval);
}
else if ((nextToken == java.io.StreamTokenizer.TT_EOF) || (nextToken == java.io.StreamTokenizer.TT_EOL))
{
keepGoing = false;
}
}
return args.toArray(new String[args.size()]);
}
private void displayUsage()
{
outputWriter.println("rhq-client.sh [-h] [-u user] [-p pass] [-s host] [-t port] [-f file]");
}
void processArguments(String[] args) throws IllegalArgumentException, IOException
{
OptionParser optionParser = new OptionParser()
{
{
acceptsAll(asList("H", "host")).withRequiredArg().ofType(String.class)
.describedAs("the JBoss AS instance's JNP host (may be a hostname or an IP address)");
acceptsAll(asList("P", "port")).withRequiredArg().ofType(Integer.class)
.describedAs("the JBoss AS instance's the JNP port");
acceptsAll(asList("u", "username")).withRequiredArg().ofType(String.class)
.describedAs("the username used to authenticate against the JBoss AS Profile Service");
acceptsAll(asList("p", "password")).withRequiredArg().ofType(String.class)
.describedAs("the password used to authenticate against the JBoss AS Profile Service");
acceptsAll(asList("e", "execute")).withRequiredArg().ofType(String.class)
.describedAs("a semicolon-separated list of commands to execute");
acceptsAll(asList("h", "?", "help"), "display help");
acceptsAll(asList("v", "verbose"), "enable verbose output");
//accepts( "output-file" ).withOptionalArg().ofType( File.class ).describedAs( "file" );
}
};
OptionSet options = optionParser.parse(args);
if (options.has("help"))
optionParser.printHelpOn(this.outputWriter);
this.host = (String)options.valueOf("host");
this.port = (Integer)options.valueOf("port");
this.username = (String)options.valueOf("username");
this.password = (String)options.valueOf("password");
this.verbose = options.has("verbose");
String execute = (String)options.valueOf("execute");
if (execute != null) {
String[] tokens = execute.split(";");
for (String token : tokens)
{
String commandName = token.trim();
if (!executeCommand(commandName))
System.exit(0);
}
}
ClientCommand connectCommand = COMMANDS.get(ConnectCommand.COMMAND_NAME);
OptionParser connectOptionParser = connectCommand.getOptionParser();
List<String> connectOptions = new ArrayList<String>();
if (this.host != null)
{
connectOptions.add("--host");
connectOptions.add(this.host);
}
if (this.port != null)
{
connectOptions.add("--port");
connectOptions.add(this.port.toString());
}
if (this.username != null)
{
connectOptions.add("--username");
connectOptions.add(this.username);
}
if (this.password != null)
{
connectOptions.add("--password");
connectOptions.add(this.password);
}
OptionSet connectOptionSet = connectOptionParser.parse(connectOptions.toArray(new String[connectOptions.size()]));
connectCommand.execute(this, connectOptionSet);
}
/*
public RHQRemoteClient getRemoteClient() {
return remoteClient;
}
public void setRemoteClient(RHQRemoteClient remoteClient) {
this.remoteClient = remoteClient;
if (remoteClient != null) {
consoleReader.addCompletor(
new ArgumentCompletor(
new Completor[]{
new SimpleCompletor("help"),
new SimpleCompletor("api"),
new SimpleCompletor(this.getRemoteClient().getAllServices().keySet().toArray(new String[this.getRemoteClient().getAllServices().size()]))}));
consoleReader.addCompletor(new ServiceCompletor(this.getRemoteClient().getAllServices()));
}
}
*/
public PrintWriter getPrintWriter()
{
return outputWriter;
}
public int getConsoleWidth()
{
return this.consoleReader.getTermwidth();
}
public Map<String, ClientCommand> getCommands()
{
return COMMANDS;
}
public ProfileServiceConnection getConnection()
{
return connection;
}
public void setConnection(ProfileServiceConnection connection)
{
this.connection = connection;
}
public void setHost(String host)
{
this.host = host;
}
public void setPort(Integer port)
{
this.port = port;
}
public boolean isVerbose()
{
return this.verbose;
}
private static <T> List<T> asList(T... items)
{
return Arrays.asList(items);
}
}