/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library 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 library 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 library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.shell;
import gnu.java.security.action.InvokeAction;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import org.jnode.shell.help.HelpFactory;
import org.jnode.shell.syntax.CommandSyntaxException;
import org.jnode.shell.io.CommandIO;
import org.jnode.vm.VmExit;
/*
* User: Sam Reid Date: Dec 20, 2003 Time: 1:20:33 AM Copyright (c) Dec 20, 2003
* by Sam Reid
*/
/**
* This CommandInvoker runs a command in the current thread, using the command
* classes <code>public static void main(String[] args)</code> entry point.
* The {@link #invokeAsynchronous(CommandLine)} method is not
* supported for this implementation of the CommandInvoker API.
*
* @author Sam Reid
* @author crawley@jnode.org
*/
public class DefaultCommandInvoker implements SimpleCommandInvoker {
private final PrintWriter err;
private final CommandShell shell;
private static final Class<?>[] MAIN_ARG_TYPES = new Class[] {String[].class};
public static final Factory FACTORY = new Factory() {
public SimpleCommandInvoker create(CommandShell shell) {
return new DefaultCommandInvoker(shell);
}
public String getName() {
return "default";
}
};
public DefaultCommandInvoker(CommandShell shell) {
this.shell = shell;
this.err = shell.resolveStream(CommandLine.DEFAULT_STDERR).getPrintWriter();
}
public String getName() {
return "default";
}
/**
* Invoke the command, running is by calling the entry point method from the
* current thread. No redirection is allowed.
*
* @param cmdLine the command line.
*/
public int invoke(CommandLine cmdLine) throws ShellException {
CommandInfo cmdInfo = cmdLine.parseCommandLine(shell);
String cmdName = cmdLine.getCommandName();
if (cmdName == null) {
return 0;
}
// FIXME ... the exception handling and error diagnosis could do with
// some reworking.
try {
final CommandIO[] ios = cmdLine.getStreams();
if (ios[0] != CommandLine.DEFAULT_STDIN ||
ios[1] != CommandLine.DEFAULT_STDOUT ||
ios[2] != CommandLine.DEFAULT_STDERR) {
err.println("Warning: redirections ignored by the '"
+ getName() + "' invoker");
}
final Method main = cmdInfo.getCommandClass().getMethod("main",
MAIN_ARG_TYPES);
int modifiers = main.getModifiers();
if ((modifiers & Modifier.STATIC) == 0 || (modifiers & Modifier.PUBLIC) == 0) {
System.err.println("The 'main' method for " + cmdInfo.getCommandClass() +
" is not public static");
return 1;
}
try {
try {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.setOut(shell.resolvePrintStream(ios[1]));
System.setErr(shell.resolvePrintStream(ios[2]));
System.setIn(shell.resolveInputStream(ios[0]));
// We've checked the method access, and we must ignore the class access.
main.setAccessible(true);
return null;
}
});
AbstractCommand.saveCurrentCommand(cmdInfo.getCommandInstance());
final Object[] args = new Object[] {cmdLine.getArguments()};
AccessController.doPrivileged(new InvokeAction(main, null, args));
return 0;
} catch (PrivilegedActionException ex) {
Exception ex2 = ex.getException();
if (ex2 instanceof InvocationTargetException) {
throw ex2.getCause();
} else {
throw ex2;
}
}
} catch (ShellControlException ex) {
throw ex;
} catch (CommandSyntaxException ex) {
HelpFactory.getHelpFactory().getHelp(cmdName, cmdInfo).usage(err);
err.println(ex.getMessage());
} catch (VmExit ex) {
return ex.getStatus();
} catch (Exception ex) {
err.println("Exception in command");
stackTrace(ex);
} catch (Throwable ex) {
err.println("Fatal error in command");
stackTrace(ex);
}
} catch (ShellControlException ex) {
throw ex;
} catch (NoSuchMethodException ex) {
err.println("Alias class has no main method " + cmdName);
} catch (ClassCastException ex) {
err.println("Invalid command " + cmdName);
} catch (Exception ex) {
err.println("I FOUND AN ERROR: " + ex);
stackTrace(ex);
} finally {
// This clears the current command to prevent leakage.
AbstractCommand.retrieveCurrentCommand();
}
return 1;
}
/**
* This method is not supported for the DefaultCommandInvoker.
*/
public CommandThread invokeAsynchronous(CommandLine commandLine) throws ShellException {
throw new UnsupportedOperationException();
}
private void stackTrace(Throwable ex) {
if (ex != null && shell.isDebugEnabled()) {
ex.printStackTrace(err);
}
}
public boolean isDebugEnabled() {
return shell.isDebugEnabled();
}
}