Revision: 5455
http://jnode.svn.sourceforge.net/jnode/?rev=5455&view=rev
Author: crawley
Date: 2009-05-07 14:27:49 +0000 (Thu, 07 May 2009)
Log Message:
-----------
This moves the instantiation of a command class and the parsing of arguments
to the child thread / proclet / isolate. It cures the problem where
a command class instance was instantiated in one isolate, then 'teleported'
to another isolate together with Argument instances ... leaving its statics
behind.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java
trunk/shell/src/shell/org/jnode/shell/CommandInfo.java
trunk/shell/src/shell/org/jnode/shell/CommandLine.java
trunk/shell/src/shell/org/jnode/shell/CommandRunner.java
trunk/shell/src/shell/org/jnode/shell/CommandShell.java
trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java
trunk/shell/src/shell/org/jnode/shell/isolate/IsolateCommandInvoker.java
trunk/shell/src/shell/org/jnode/shell/proclet/ProcletCommandInvoker.java
Modified: trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java 2009-05-07 08:27:00 UTC (rev 5454)
+++ trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java 2009-05-07 14:27:49 UTC (rev 5455)
@@ -21,10 +21,6 @@
package org.jnode.shell;
import java.awt.event.KeyEvent;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
@@ -53,17 +49,6 @@
protected final CommandShell shell;
- static final Class<?>[] MAIN_ARG_TYPES = new Class[] {String[].class};
-
- static final Class<?>[] EXECUTE_ARG_TYPES = new Class[] {
- CommandLine.class, InputStream.class, PrintStream.class,
- PrintStream.class
- };
-
- static final String MAIN_METHOD = "main";
-
- static final String EXECUTE_METHOD = "execute";
-
boolean blocking;
Thread blockingThread;
@@ -83,28 +68,22 @@
}
public int invoke(CommandLine commandLine) throws ShellException {
- CommandInfo cmdInfo = commandLine.parseCommandLine(shell);
- CommandRunner cr = setup(commandLine, cmdInfo);
- return runIt(commandLine, cmdInfo, cr);
+ CommandRunner cr = setup(commandLine);
+ return runIt(commandLine, cr);
}
public CommandThread invokeAsynchronous(CommandLine commandLine) throws ShellException {
- CommandInfo cmdInfo = commandLine.parseCommandLine(shell);
- CommandRunner cr = setup(commandLine, cmdInfo);
- return forkIt(commandLine, cmdInfo, cr);
+ CommandRunner cr = setup(commandLine);
+ return forkIt(commandLine, cr);
}
- protected CommandRunner setup(CommandLine cmdLine, CommandInfo cmdInfo)
+ protected CommandRunner setup(CommandLine cmdLine)
throws ShellException {
- return setup(cmdLine, cmdInfo, null, null);
+ return setup(cmdLine, null, null);
}
- protected CommandRunner setup(CommandLine cmdLine, CommandInfo cmdInfo,
- Properties sysProps, Map<String, String> env)
+ protected CommandRunner setup(CommandLine cmdLine, Properties sysProps, Map<String, String> env)
throws ShellException {
- Method method;
- CommandRunner cr = null;
-
CommandIO[] ios = cmdLine.getStreams();
boolean redirected = ios[Command.STD_IN] != CommandLine.DEFAULT_STDIN ||
ios[Command.STD_OUT] != CommandLine.DEFAULT_STDOUT ||
@@ -114,45 +93,12 @@
} catch (ClassCastException ex) {
throw new ShellFailureException("streams array broken", ex);
}
- Command command;
- try {
- command = cmdInfo.createCommandInstance();
- } catch (Exception ex) {
- throw new ShellInvocationException("Problem while creating command instance", ex);
- }
- if (command != null) {
- cr = new CommandRunner(this, cmdInfo, cmdLine, ios, sysProps, env);
- } else {
- try {
- method = cmdInfo.getCommandClass().getMethod(MAIN_METHOD, MAIN_ARG_TYPES);
- int modifiers = method.getModifiers();
- if ((modifiers & Modifier.STATIC) == 0 || (modifiers & Modifier.PUBLIC) == 0) {
- new ShellInvocationException("The 'main' method for " +
- cmdInfo.getCommandClass() + " is not public static");
- }
- if (redirected) {
- throw new ShellInvocationException(
- "The 'main' method for " + cmdInfo.getCommandClass() +
- " does not allow redirection or pipelining");
- }
- // We've checked the method access, and we must ignore the class access.
- method.setAccessible(true);
- cr = new CommandRunner(
- this, cmdInfo, cmdInfo.getCommandClass(), method,
- new Object[] {cmdLine.getArguments()}, ios, sysProps, env);
- } catch (NoSuchMethodException e) {
- // continue;
- }
- if (cr == null) {
- throw new ShellInvocationException(
- "No entry point method found for " + cmdInfo.getCommandClass());
- }
- }
- return cr;
+ CommandInfo cmdInfo = shell.getCommandInfo(cmdLine.getCommandName());
+ return new CommandRunner(this, cmdLine, cmdInfo, ios, sysProps, env, redirected);
}
- protected int runIt(CommandLine cmdLine, CommandInfo cmdInfo, CommandRunner cr)
- throws ShellInvocationException {
+ protected int runIt(CommandLine cmdLine, CommandRunner cr) throws ShellInvocationException {
+ CommandInfo cmdInfo = cr.getCommandInfo();
try {
if (cmdInfo.isInternal()) {
cr.run();
@@ -172,8 +118,7 @@
}
return cr.getRC();
} catch (Exception ex) {
- throw new ShellInvocationException("Uncaught Exception in command",
- ex);
+ throw new ShellInvocationException("Uncaught Exception in command", ex);
} catch (Error ex) {
throw new ShellInvocationException("Fatal Error in command", ex);
} finally {
@@ -182,8 +127,8 @@
}
}
- protected CommandThread forkIt(CommandLine cmdLine, CommandInfo cmdInfo,
- CommandRunner cr) throws ShellInvocationException {
+ protected CommandThread forkIt(CommandLine cmdLine, CommandRunner cr) throws ShellInvocationException {
+ CommandInfo cmdInfo = cr.getCommandInfo();
if (cmdInfo.isInternal()) {
throw new ShellFailureException("unexpected internal command");
}
Modified: trunk/shell/src/shell/org/jnode/shell/CommandInfo.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandInfo.java 2009-05-07 08:27:00 UTC (rev 5454)
+++ trunk/shell/src/shell/org/jnode/shell/CommandInfo.java 2009-05-07 14:27:49 UTC (rev 5455)
@@ -20,6 +20,10 @@
package org.jnode.shell;
+import org.jnode.shell.syntax.ArgumentBundle;
+import org.jnode.shell.syntax.CommandSyntaxException;
+import org.jnode.shell.syntax.SyntaxBundle;
+
/**
* A CommandInfo object is a descriptor used by the CommandShell and CommandInvokers
* to hold information about a command that is being prepared for execution.
@@ -30,14 +34,17 @@
public final class CommandInfo {
private final Class<?> clazz;
-
+ private final String commandName;
+ private final SyntaxBundle syntaxBundle;
private final boolean internal;
private Command instance;
- public CommandInfo(Class<?> clazz, boolean internal) {
+ public CommandInfo(Class<?> clazz, String commandName, SyntaxBundle syntaxBundle, boolean internal) {
this.clazz = clazz;
this.internal = internal;
+ this.commandName = commandName;
+ this.syntaxBundle = syntaxBundle;
}
public final Class<?> getCommandClass() {
@@ -72,4 +79,37 @@
public Command getCommandInstance() {
return instance;
}
+
+ public String getCommandName() {
+ return commandName;
+ }
+
+ /**
+ * Perform command line argument parsing in preparation to invoking a command.
+ * This locates the command's class and a suitable command line syntax, then
+ * parses against the Syntax, binding the command arguments to Argument objects
+ * in an ArgumentBundle object obtained from the Command object.
+ *
+ * @param shell the context for resolving command aliases and locating syntaxes
+ * @throws CommandSyntaxException if the chosen syntax doesn't match the command
+ * line arguments.
+ * @throws ShellException for problems instantiating the command class.
+ */
+ public void parseCommandLine(CommandLine cmdLine) throws ShellException {
+ try {
+ Command command = createCommandInstance();
+
+ // Get the command's argument bundle, or the default one.
+ ArgumentBundle bundle = (command == null) ? null : command.getArgumentBundle();
+ if (bundle != null) {
+ // Do a full parse to bind the command line argument tokens to corresponding
+ // command arguments
+ bundle.parse(cmdLine, syntaxBundle);
+ }
+ } catch (InstantiationException ex) {
+ throw new ShellException("Command class cannot be instantiated", ex);
+ } catch (IllegalAccessException ex) {
+ throw new ShellException("Command class cannot be instantiated", ex);
+ }
+ }
}
Modified: trunk/shell/src/shell/org/jnode/shell/CommandLine.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandLine.java 2009-05-07 08:27:00 UTC (rev 5454)
+++ trunk/shell/src/shell/org/jnode/shell/CommandLine.java 2009-05-07 14:27:49 UTC (rev 5455)
@@ -565,6 +565,10 @@
* This locates the command's class and a suitable command line syntax, then
* parses against the Syntax, binding the command arguments to Argument objects
* in an ArgumentBundle object obtained from the Command object.
+ * <p>
+ * Note that the async invokers don't use this method. Instead, they obtain the
+ * CommandInfo in the parent thread, then create the command instance and do
+ * the argument parsing in the child thread / proclet / isolate.
*
* @param shell the context for resolving command aliases and locating syntaxes
* @return a CompandInfo which includes the command instance to which the arguments have been bound
@@ -576,28 +580,9 @@
if (cmd.equals("")) {
throw new ShellFailureException("no command name");
}
- try {
- // Get command's argument bundle and syntax
- CommandInfo cmdInfo = shell.getCommandInfo(cmd);
- Command command = cmdInfo.createCommandInstance();
-
- // Get the command's argument bundle, or the default one.
- ArgumentBundle bundle = (command == null) ? null :
- command.getArgumentBundle();
- if (bundle != null) {
- // Get a syntax for the alias, or a default one.
- SyntaxBundle syntaxes = shell.getSyntaxManager().getSyntaxBundle(cmd);
-
- // Do a full parse to bind the command line argument tokens to corresponding
- // command arguments
- bundle.parse(this, syntaxes);
- }
- return cmdInfo;
- } catch (InstantiationException ex) {
- throw new ShellException("Command class cannot be instantiated", ex);
- } catch (IllegalAccessException ex) {
- throw new ShellException("Command class cannot be instantiated", ex);
- }
+ CommandInfo cmdInfo = shell.getCommandInfo(cmd);
+ cmdInfo.parseCommandLine(this);
+ return cmdInfo;
}
public void complete(CompletionInfo completion, CommandShell shell) throws CompletionException {
Modified: trunk/shell/src/shell/org/jnode/shell/CommandRunner.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandRunner.java 2009-05-07 08:27:00 UTC (rev 5454)
+++ trunk/shell/src/shell/org/jnode/shell/CommandRunner.java 2009-05-07 14:27:49 UTC (rev 5455)
@@ -23,6 +23,8 @@
import gnu.java.security.action.InvokeAction;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -46,90 +48,49 @@
* @author crawley@...
*/
public class CommandRunner implements CommandRunnable {
+
+ static final Class<?>[] MAIN_ARG_TYPES = new Class[] {String[].class};
+
+ static final Class<?>[] EXECUTE_ARG_TYPES = new Class[] {
+ CommandLine.class, InputStream.class, PrintStream.class,
+ PrintStream.class
+ };
+
+ static final String MAIN_METHOD = "main";
+
+ static final String EXECUTE_METHOD = "execute";
private final SimpleCommandInvoker invoker;
private final CommandIO[] ios;
- final Class<?> targetClass;
- final Method method;
- final Object[] args;
- final CommandInfo cmdInfo;
final CommandLine commandLine;
final PrintWriter shellErr;
final Properties sysProps;
final Map<String, String> env;
+ final boolean redirected;
+ final CommandInfo cmdInfo;
+
+ Class<?> targetClass;
+ Method method;
+ Object[] args;
private int rc;
- public CommandRunner(SimpleCommandInvoker invoker,
- CommandInfo cmdInfo, Class<?> targetClass, Method method, Object[] args,
- CommandIO[] ios, Properties sysProps, Map<String, String> env) {
+ public CommandRunner(SimpleCommandInvoker invoker, CommandLine commandLine, CommandInfo cmdInfo, CommandIO[] ios,
+ Properties sysProps, Map<String, String> env, boolean redirected) {
this.invoker = invoker;
- this.targetClass = targetClass;
- this.method = method;
+ this.redirected = redirected;
+ this.commandLine = commandLine;
this.cmdInfo = cmdInfo;
- this.commandLine = null;
- this.args = args;
this.ios = ios;
this.shellErr = ios[Command.SHELL_ERR].getPrintWriter();
this.env = env;
this.sysProps = sysProps;
}
- public CommandRunner(SimpleCommandInvoker invoker,
- CommandInfo cmdInfo, CommandLine commandLine, CommandIO[] ios,
- Properties sysProps, Map<String, String> env) {
- this.invoker = invoker;
- this.targetClass = null;
- this.method = null;
- this.args = null;
- this.cmdInfo = cmdInfo;
- this.commandLine = commandLine;
- this.ios = ios;
- this.shellErr = ios[Command.SHELL_ERR].getPrintWriter();
- this.env = env;
- this.sysProps = sysProps;
- }
-
public void run() {
try {
- try {
- if (method != null) {
- try {
- // This saves the Command instance that has the command line state
- // associated in a thread-local so that the Abstract.execute(String[])
- // method can get hold of it. This is the magic that allows a command
- // that implements 'main' as "new MyCommand().execute(args)" to get the
- // parsed command line arguments, etc.
- AbstractCommand.saveCurrentCommand(cmdInfo.getCommandInstance());
-
- // Call the command's entry point method reflectively
- Object obj = Modifier.isStatic(method.getModifiers()) ? null
- : targetClass.newInstance();
- AccessController.doPrivileged(new InvokeAction(method, obj,
- args));
- } finally {
- // This clears the current command to prevent possible leakage of
- // commands arguments, etc to the next command.
- AbstractCommand.retrieveCurrentCommand();
- }
- } else {
- // For a command that implements the Command API, call the 'new'
- // execute method. If it is not 'execute()' is not overridden by the
- // command class, the default implementation from AbstractCommand will
- // bounce us to the older execute(CommandLine, InputStream, PrintStream,
- // PrintStream) method.
- Command cmd = cmdInfo.createCommandInstance();
- cmd.initialize(commandLine, getIOs());
- cmd.execute();
- }
- } catch (PrivilegedActionException ex) {
- Exception ex2 = ex.getException();
- if (ex2 instanceof InvocationTargetException) {
- throw ex2.getCause();
- } else {
- throw ex2;
- }
- }
+ prepare();
+ execute();
} catch (SyntaxErrorException ex) {
try {
HelpFactory.getHelpFactory().getHelp(commandLine.getCommandName(), cmdInfo).usage(shellErr);
@@ -149,6 +110,80 @@
}
}
+ private void prepare() throws ShellException {
+ Command command;
+ try {
+ command = cmdInfo.createCommandInstance();
+ } catch (Exception ex) {
+ throw new ShellInvocationException("Problem while creating command instance", ex);
+ }
+ if (command == null) {
+ try {
+ method = cmdInfo.getCommandClass().getMethod(MAIN_METHOD, MAIN_ARG_TYPES);
+ int modifiers = method.getModifiers();
+ if ((modifiers & Modifier.STATIC) == 0 || (modifiers & Modifier.PUBLIC) == 0) {
+ new ShellInvocationException("The 'main' method for " +
+ cmdInfo.getCommandClass() + " is not public static");
+ }
+ if (redirected) {
+ throw new ShellInvocationException(
+ "The 'main' method for " + cmdInfo.getCommandClass() +
+ " does not allow redirection or pipelining");
+ }
+ // We've checked the method access, and we must ignore the class access.
+ method.setAccessible(true);
+ targetClass = cmdInfo.getCommandClass();
+ args = new Object[] {commandLine.getArguments()};
+ } catch (NoSuchMethodException e) {
+ throw new ShellInvocationException(
+ "No entry point method found for " + cmdInfo.getCommandClass());
+ }
+ } else {
+ cmdInfo.parseCommandLine(commandLine);
+ }
+ }
+
+ private void execute() throws Throwable {
+ try {
+ if (method != null) {
+ try {
+ // This saves the Command instance that has the command line state
+ // associated in a thread-local so that the Abstract.execute(String[])
+ // method can get hold of it. This is the magic that allows a command
+ // that implements 'main' as "new MyCommand().execute(args)" to get the
+ // parsed command line arguments, etc.
+ AbstractCommand.saveCurrentCommand(cmdInfo.getCommandInstance());
+
+ // Call the command's entry point method reflectively
+ Object obj = Modifier.isStatic(method.getModifiers()) ? null
+ : targetClass.newInstance();
+ AccessController.doPrivileged(new InvokeAction(method, obj,
+ args));
+ } finally {
+ // This clears the current command to prevent possible leakage of
+ // commands arguments, etc to the next command.
+ AbstractCommand.retrieveCurrentCommand();
+ }
+ } else {
+ // For a command that implements the Command API, call the 'new'
+ // execute method. If it is not 'execute()' is not overridden by the
+ // command class, the default implementation from AbstractCommand will
+ // bounce us to the older execute(CommandLine, InputStream, PrintStream,
+ // PrintStream) method.
+ Command cmd = cmdInfo.createCommandInstance();
+ cmd.initialize(commandLine, getIOs());
+ cmd.execute();
+ }
+ } catch (PrivilegedActionException ex) {
+ Exception ex2 = ex.getException();
+ if (ex2 instanceof InvocationTargetException) {
+ throw ex2.getCause();
+ } else {
+ throw ex2;
+ }
+ }
+ }
+
public int getRC() {
return rc;
}
Modified: trunk/shell/src/shell/org/jnode/shell/CommandShell.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2009-05-07 08:27:00 UTC (rev 5454)
+++ trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2009-05-07 14:27:49 UTC (rev 5455)
@@ -71,6 +71,7 @@
import org.jnode.shell.proclet.ProcletCommandInvoker;
import org.jnode.shell.syntax.ArgumentBundle;
import org.jnode.shell.syntax.CommandSyntaxException;
+import org.jnode.shell.syntax.SyntaxBundle;
import org.jnode.shell.syntax.SyntaxManager;
import org.jnode.shell.syntax.CommandSyntaxException.Context;
import org.jnode.util.ReaderInputStream;
@@ -662,16 +663,17 @@
}
public CommandInfo getCommandInfo(String cmd) throws ShellException {
+ SyntaxBundle syntaxBundle = getSyntaxManager().getSyntaxBundle(cmd);
try {
Class<?> cls = aliasMgr.getAliasClass(cmd);
- return new CommandInfo(cls, aliasMgr.isInternal(cmd));
+ return new CommandInfo(cls, cmd, syntaxBundle, aliasMgr.isInternal(cmd));
} catch (ClassNotFoundException ex) {
throw new ShellException("Cannot the load command class for alias '" + cmd + "'", ex);
} catch (NoSuchAliasException ex) {
try {
final ClassLoader cl =
Thread.currentThread().getContextClassLoader();
- return new CommandInfo(cl.loadClass(cmd), false);
+ return new CommandInfo(cl.loadClass(cmd), cmd, syntaxBundle, false);
} catch (ClassNotFoundException ex2) {
throw new ShellException(
"Cannot find an alias or load a command class for '" + cmd + "'", ex);
Modified: trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java 2009-05-07 08:27:00 UTC (rev 5454)
+++ trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java 2009-05-07 14:27:49 UTC (rev 5455)
@@ -163,8 +163,8 @@
}
}
- @Override
public boolean isDebugEnabled() {
return shell.isDebugEnabled();
}
+
}
Modified: trunk/shell/src/shell/org/jnode/shell/isolate/IsolateCommandInvoker.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/isolate/IsolateCommandInvoker.java 2009-05-07 08:27:00 UTC (rev 5454)
+++ trunk/shell/src/shell/org/jnode/shell/isolate/IsolateCommandInvoker.java 2009-05-07 14:27:49 UTC (rev 5455)
@@ -25,7 +25,6 @@
import java.util.Properties;
import org.jnode.shell.AsyncCommandInvoker;
-import org.jnode.shell.CommandInfo;
import org.jnode.shell.CommandInvoker;
import org.jnode.shell.CommandLine;
import org.jnode.shell.CommandRunner;
@@ -63,16 +62,14 @@
public int invoke(CommandLine commandLine, Properties sysProps, Map<String, String> env)
throws ShellException {
- CommandInfo cmdInfo = commandLine.parseCommandLine(shell);
- CommandRunner cr = setup(commandLine, cmdInfo, sysProps, env);
- return runIt(commandLine, cmdInfo, cr);
+ CommandRunner cr = setup(commandLine, sysProps, env);
+ return runIt(commandLine, cr);
}
public CommandThread invokeAsynchronous(CommandLine commandLine, Properties sysProps,
Map<String, String> env) throws ShellException {
- CommandInfo cmdInfo = commandLine.parseCommandLine(shell);
- CommandRunner cr = setup(commandLine, cmdInfo, sysProps, env);
- return forkIt(commandLine, cmdInfo, cr);
+ CommandRunner cr = setup(commandLine, sysProps, env);
+ return forkIt(commandLine, cr);
}
@Override
Modified: trunk/shell/src/shell/org/jnode/shell/proclet/ProcletCommandInvoker.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/proclet/ProcletCommandInvoker.java 2009-05-07 08:27:00 UTC (rev 5454)
+++ trunk/shell/src/shell/org/jnode/shell/proclet/ProcletCommandInvoker.java 2009-05-07 14:27:49 UTC (rev 5455)
@@ -25,7 +25,6 @@
import org.jnode.shell.AsyncCommandInvoker;
import org.jnode.shell.Command;
-import org.jnode.shell.CommandInfo;
import org.jnode.shell.CommandInvoker;
import org.jnode.shell.CommandLine;
import org.jnode.shell.CommandRunner;
@@ -69,16 +68,14 @@
public int invoke(CommandLine commandLine, Properties sysProps, Map<String, String> env)
throws ShellException {
- CommandInfo cmdInfo = commandLine.parseCommandLine(shell);
- CommandRunner cr = setup(commandLine, cmdInfo, sysProps, env);
- return runIt(commandLine, cmdInfo, cr);
+ CommandRunner cr = setup(commandLine, sysProps, env);
+ return runIt(commandLine, cr);
}
public CommandThread invokeAsynchronous(CommandLine commandLine, Properties sysProps,
Map<String, String> env) throws ShellException {
- CommandInfo cmdInfo = commandLine.parseCommandLine(shell);
- CommandRunner cr = setup(commandLine, cmdInfo, sysProps, env);
- return forkIt(commandLine, cmdInfo, cr);
+ CommandRunner cr = setup(commandLine, sysProps, env);
+ return forkIt(commandLine, cr);
}
protected CommandThreadImpl createThread(CommandRunner cr) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|