From: <ls...@us...> - 2007-08-23 20:59:29
|
Revision: 3400 http://jnode.svn.sourceforge.net/jnode/?rev=3400&view=rev Author: lsantha Date: 2007-08-23 13:59:27 -0700 (Thu, 23 Aug 2007) Log Message: ----------- Reworked the patch sent by crawley for proclet support in jnode, to factor out proclets from the vm into org.jnode.shell.proclet package under the shell project. Modified Paths: -------------- trunk/builder/src/builder/org/jnode/ant/taskdefs/AnnotateTask.java trunk/core/src/core/org/jnode/vm/VmSystem.java trunk/core/src/driver/org/jnode/driver/console/textscreen/TextScreenConsole.java trunk/fs/descriptors/org.jnode.fs.command.xml trunk/fs/descriptors/org.jnode.fs.xml trunk/shell/descriptors/org.jnode.shell.command.driver.console.xml trunk/shell/descriptors/org.jnode.shell.xml trunk/shell/src/shell/org/jnode/shell/CommandShell.java trunk/shell/src/shell/org/jnode/shell/ThreadCommandInvoker.java Added Paths: ----------- trunk/core/src/core/org/jnode/vm/IOContext.java trunk/core/src/core/org/jnode/vm/VmIOContext.java trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java trunk/shell/src/shell/org/jnode/shell/ProcletCommandInvoker.java trunk/shell/src/shell/org/jnode/shell/proclet/ trunk/shell/src/shell/org/jnode/shell/proclet/AbstractProxyPrintStream.java trunk/shell/src/shell/org/jnode/shell/proclet/ProcletContext.java trunk/shell/src/shell/org/jnode/shell/proclet/ProcletException.java trunk/shell/src/shell/org/jnode/shell/proclet/ProcletIOContext.java trunk/shell/src/shell/org/jnode/shell/proclet/ProcletProxyInputStream.java trunk/shell/src/shell/org/jnode/shell/proclet/ProcletProxyPrintStream.java trunk/shell/src/shell/org/jnode/shell/proclet/ProcletProxyStream.java trunk/shell/src/shell/org/jnode/shell/proclet/ProxyStream.java trunk/shell/src/shell/org/jnode/shell/proclet/ProxyStreamException.java Modified: trunk/builder/src/builder/org/jnode/ant/taskdefs/AnnotateTask.java =================================================================== --- trunk/builder/src/builder/org/jnode/ant/taskdefs/AnnotateTask.java 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/builder/src/builder/org/jnode/ant/taskdefs/AnnotateTask.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -229,13 +229,11 @@ ClassWriter cw = new ClassWriter(false); try { ClassReader cr = new ClassReader(inputClass); - cr.accept(new MarkerClassVisitor(cw), - AbstractVisitor.getDefaultAttributes(), false); - + cr.accept(new MarkerClassVisitor(cw), AbstractVisitor.getDefaultAttributes(), false); byte[] b = cw.toByteArray(); outputClass.write(b); } catch (Exception ex) { - throw new BuildException("Unable to load class in file "+fileName); + throw new BuildException("Unable to load class in file "+fileName, ex); } } Added: trunk/core/src/core/org/jnode/vm/IOContext.java =================================================================== --- trunk/core/src/core/org/jnode/vm/IOContext.java (rev 0) +++ trunk/core/src/core/org/jnode/vm/IOContext.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -0,0 +1,24 @@ +/* + * $Id$ + */ +package org.jnode.vm; + +import java.io.InputStream; +import java.io.PrintStream; + +/** + * @author Levente S\xE1ntha + */ +public interface IOContext { + void setGlobalInStream(InputStream in); + InputStream getGlobalInStream(); + void setGlobalOutStream(PrintStream out); + PrintStream getGlobalOutStream(); + void setGlobalErrStream(PrintStream err); + PrintStream getGlobalErrStream(); + void setSystemIn(InputStream in); + void setSystemOut(PrintStream out); + void setSystemErr(PrintStream err); + void enterContext(); + void exitContext(); +} Added: trunk/core/src/core/org/jnode/vm/VmIOContext.java =================================================================== --- trunk/core/src/core/org/jnode/vm/VmIOContext.java (rev 0) +++ trunk/core/src/core/org/jnode/vm/VmIOContext.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -0,0 +1,63 @@ +/* + * $Id$ + */ +package org.jnode.vm; + +import java.io.InputStream; +import java.io.PrintStream; + +/** + * @author Levente S\xE1ntha + */ +class VmIOContext implements IOContext { + private static InputStream globalInStream; + private static PrintStream globalOutStream; + private static PrintStream globalErrStream; + + public void setGlobalInStream(InputStream in) { + globalInStream = in; + } + + public void setGlobalOutStream(PrintStream out) { + globalOutStream = out; + } + + public PrintStream getGlobalOutStream() { + return globalOutStream; + } + + public void setGlobalErrStream(PrintStream err) { + globalErrStream = err; + } + + public PrintStream getGlobalErrStream(){ + return globalErrStream; + } + + public InputStream getGlobalInStream() { + return globalInStream; + } + + public void setSystemIn(InputStream in) { + globalInStream = in; + VmSystem.setStaticField(System.class, "in", in); + } + + public void setSystemOut(PrintStream out) { + globalOutStream = out; + VmSystem.setStaticField(System.class, "out", out); + } + + public void setSystemErr(PrintStream err) { + globalErrStream = err; + VmSystem.setStaticField(System.class, "err", err); + } + + public void enterContext() { + + } + + public void exitContext() { + + } +} Modified: trunk/core/src/core/org/jnode/vm/VmSystem.java =================================================================== --- trunk/core/src/core/org/jnode/vm/VmSystem.java 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/core/src/core/org/jnode/vm/VmSystem.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -43,7 +43,6 @@ import org.jnode.system.ResourceNotFreeException; import org.jnode.system.ResourceOwner; import org.jnode.system.SimpleResourceOwner; -import org.jnode.util.SystemInputStream; import org.jnode.vm.annotation.Internal; import org.jnode.vm.annotation.KernelSpace; import org.jnode.vm.annotation.MagicPermission; @@ -213,6 +212,10 @@ if (bootOut == null) { bootOut = new SystemOutputStream(); bootOutStream = new PrintStream(bootOut, true); + //globalOutStream = globalErrStream = bootOutStream; + ioContext.setGlobalOutStream(bootOutStream); + ioContext.setGlobalErrStream(bootOutStream); + } return bootOutStream; } @@ -969,42 +972,50 @@ } /** - * Set in to a new InputStream. + * Set the effective System.in to a different InputStream. The actual behavior depends + * on whether we're in proclet mode or not. If we are, we set the appropriate proxied stream, + * to the new stream, depending on whether the current thread is a ProcletContext or not. + * Otherwise, we update the System.in field. * - * @param in - * the new InputStream + * @param in the new InputStream * @see #setIn(InputStream) */ + @PrivilegedActionPragma public static void setIn(InputStream in) { - SystemInputStream.getInstance().setIn(in); + ioContext.setSystemIn(in); } /** - * Set {@link #out}to a new PrintStream. + * Set the effective System.out to a different PrintStream. The actual behavior depends + * on whether we're in proclet mode or not. If we are, we set the appropriate proxied stream, + * to the new stream, depending on whether the current thread is a ProcletContext or not. + * Otherwise, we update the System.out field. * - * @param out - * the new PrintStream - * @see #setOut(PrintStream) + * @param out the new PrintStream + * @see java.lang.System#setOut(PrintStream) */ @PrivilegedActionPragma public static void setOut(PrintStream out) { - setStaticField(System.class, "out", out); + ioContext.setSystemOut(out); } /** - * Set err to a new PrintStream. + * Set the effective System.err to a different PrintStream. The actual behavior depends + * on whether we're in proclet mode or not. If we are, we set the appropriate proxied stream, + * to the new stream, depending on whether the current thread is a ProcletContext or not. + * Otherwise, we update the System.err field. * - * @param err - * the new PrintStream - * @see #setErr(PrintStream) + * @param err the new PrintStream + * @see java.lang.System#setErr(PrintStream) */ @PrivilegedActionPragma public static void setErr(PrintStream err) { - setStaticField(System.class, "err", err); + ioContext.setSystemErr(err); } + //todo protect this method from arbitrary access @PrivilegedActionPragma - private static void setStaticField(Class< ? > clazz, String fieldName, + public static void setStaticField(Class< ? > clazz, String fieldName, Object value) { final VmStaticField f = (VmStaticField) clazz.getVmClass().getField( fieldName); @@ -1020,4 +1031,56 @@ final Address ptr = VmMagic.getArrayData(staticsTable); ptr.store(ObjectReference.fromObject(value), offset); } + + //io context related + private static final IOContext vmIoContext = new VmIOContext(); + private static IOContext ioContext = vmIoContext; + + public static boolean hasVmIOContext(){ + return ioContext instanceof VmIOContext; + } + + + /** + * Get the current global (i.e. non-ProcletContext) flavor of System.err. + * + * @return the global 'err' stream. + */ + public static PrintStream getGlobalErrStream() { + return ioContext.getGlobalErrStream(); + } + + /** + * Get the current global (i.e. non-ProcletContext) flavor of System.in. + * + * @return the global 'in' stream. + */ + public static InputStream getGlobalInStream() { + return ioContext.getGlobalInStream(); + } + + /** + * Get the current global (i.e. non-ProcletContext) flavor of System.out. + * + * @return the global 'out' stream. + */ + public static PrintStream getGlobalOutStream() { + return ioContext.getGlobalOutStream(); + } + + public static void switchToExternalIOContext(IOContext context){ + if (hasVmIOContext()){ + ioContext = context; + context.enterContext(); + } + } + + public static void resetIOContext(){ + if (!hasVmIOContext()){ + ioContext.exitContext(); + ioContext = vmIoContext; + } else { + throw new RuntimeException("IO Context cannot be reset"); + } + } } Modified: trunk/core/src/driver/org/jnode/driver/console/textscreen/TextScreenConsole.java =================================================================== --- trunk/core/src/driver/org/jnode/driver/console/textscreen/TextScreenConsole.java 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/core/src/driver/org/jnode/driver/console/textscreen/TextScreenConsole.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -35,6 +35,7 @@ import org.jnode.driver.textscreen.TextScreen; import org.jnode.system.event.FocusEvent; import org.jnode.system.event.FocusListener; +import org.jnode.vm.VmSystem; import org.jnode.vm.isolate.VmIsolate; /** @@ -363,7 +364,7 @@ if (in instanceof FocusListener) { ((FocusListener) in).focusGained(event); } - if (claimSystemOutErr) { + if (claimSystemOutErr && VmSystem.hasVmIOContext()) { myIsolate.invokeAndWait(new Runnable() { public void run() { AccessController.doPrivileged(new PrivilegedAction<Object>() { @@ -385,7 +386,7 @@ if (in instanceof FocusListener) { ((FocusListener) in).focusLost(event); } - if (claimSystemOutErr) { + if (claimSystemOutErr && VmSystem.hasVmIOContext()) { myIsolate.invokeAndWait(new Runnable() { public void run() { savedOut = System.out; Modified: trunk/fs/descriptors/org.jnode.fs.command.xml =================================================================== --- trunk/fs/descriptors/org.jnode.fs.command.xml 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/fs/descriptors/org.jnode.fs.command.xml 2007-08-23 20:59:27 UTC (rev 3400) @@ -39,7 +39,8 @@ <permission class="java.net.SocketPermission" name="*:0-" actions="connect,resolve"/> <permission class="java.util.PropertyPermission" name="user.dir" actions="read,write"/> <permission class="java.util.PropertyPermission" name="*" actions="read,write"/> - <permission class="java.net.NetPermission" name="specifyStreamHandler"/> + <permission class="java.net.NetPermission" name="specifyStreamHandler"/> + <permission class="java.lang.RuntimePermission" name="modifyThreadGroup"/> </extension> </plugin> Modified: trunk/fs/descriptors/org.jnode.fs.xml =================================================================== --- trunk/fs/descriptors/org.jnode.fs.xml 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/fs/descriptors/org.jnode.fs.xml 2007-08-23 20:59:27 UTC (rev 3400) @@ -32,6 +32,7 @@ <permission class="java.net.SocketPermission" name="*:0-" actions="connect,resolve"/> <permission class="java.net.NetPermission" name="specifyStreamHandler"/> <permission class="java.util.PropertyPermission" name="*" actions="read,write"/> + <permission class="java.lang.RuntimePermission" name="modifyThreadGroup"/> </extension> </plugin> Modified: trunk/shell/descriptors/org.jnode.shell.command.driver.console.xml =================================================================== --- trunk/shell/descriptors/org.jnode.shell.command.driver.console.xml 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/shell/descriptors/org.jnode.shell.command.driver.console.xml 2007-08-23 20:59:27 UTC (rev 3400) @@ -23,6 +23,15 @@ </extension> <extension point="org.jnode.security.permissions"> - <permission class="java.util.PropertyPermission" name="jnode.prompt" actions="read"/> + <permission class="java.io.FilePermission" name="<<ALL FILES>>" actions="read,write"/> + <permission class="java.lang.RuntimePermission" name="modifyThreadGroup"/> + <permission class="java.lang.RuntimePermission" name="modifyThread"/> + <permission class="java.lang.RuntimePermission" name="setIO"/> + <permission class="java.net.SocketPermission" name="*" actions="resolve,listen,connect"/> + <permission class="java.net.SocketPermission" name="*:0-" actions="connect,resolve,listen"/> + <permission class="java.util.PropertyPermission" name="jnode.cmdline" actions="read"/> + <permission class="java.util.PropertyPermission" name="jnode.invoker" actions="read"/> + <permission class="java.util.PropertyPermission" name="jnode.prompt" actions="read,write"/> + <permission class="java.util.PropertyPermission" name="user.dir" actions="read"/> </extension> </plugin> \ No newline at end of file Modified: trunk/shell/descriptors/org.jnode.shell.xml =================================================================== --- trunk/shell/descriptors/org.jnode.shell.xml 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/shell/descriptors/org.jnode.shell.xml 2007-08-23 20:59:27 UTC (rev 3400) @@ -23,6 +23,7 @@ <export name="org.jnode.shell.help.*"/> <export name="org.jnode.shell.help.argument.*"/> <export name="org.jnode.shell.help.def.*"/> + <export name="org.jnode.shell.proclet.*"/> </library> </runtime> @@ -36,7 +37,9 @@ <permission class="java.net.SocketPermission" name="*" actions="resolve,listen,connect"/> <permission class="java.net.SocketPermission" name="*:0-" actions="connect,resolve,listen"/> <permission class="java.util.PropertyPermission" name="jnode.cmdline" actions="read"/> + <permission class="java.util.PropertyPermission" name="jnode.invoker" actions="read"/> <permission class="java.util.PropertyPermission" name="jnode.prompt" actions="read,write"/> + <permission class="java.util.PropertyPermission" name="*" actions="read,write"/> <permission class="java.util.PropertyPermission" name="user.dir" actions="read"/> </extension> Added: trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java (rev 0) +++ trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -0,0 +1,281 @@ +/* + * $Id: ThreadCommandInvoker.java 3374 2007-08-02 18:15:27Z lsantha $ + * + * JNode.org + * Copyright (C) 2003-2006 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.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +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.driver.input.KeyboardEvent; +import org.jnode.driver.input.KeyboardListener; +import org.jnode.shell.help.Help; +import org.jnode.shell.help.HelpException; +import org.jnode.shell.help.SyntaxErrorException; +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 + * + * @author Sam Reid + * @author Martin Husted Hartvig (ha...@jn...) + * @author cr...@jn... + */ +public abstract class AsyncCommandInvoker implements CommandInvoker, KeyboardListener { + + PrintStream err; + + CommandShell commandShell; + + 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; + + Thread threadProcess = null; + + String cmdName; + + public AsyncCommandInvoker(CommandShell commandShell) { + this.commandShell = commandShell; + this.err = commandShell.getErrorStream(); + commandShell.getConsole().addKeyboardListener(this);// listen for + // ctrl-c + } + + public void invoke(String cmdLineStr) { + commandShell.addCommandToHistory(cmdLineStr); + + InputStream inputStream = commandShell.getInputStream(); + InputStream nextInputStream = null; + PrintStream errStream = commandShell.getErrorStream(); + PrintStream outputStream = null; + boolean mustCloseOutputStream = false; + + CommandLine cmdLine; + Method method; + Runnable cr; + CommandInfo cmdInfo; + + String[] commands = cmdLineStr.split("\\|"); + String command; + ByteArrayOutputStream byteArrayOutputStream = null; + + for (int i = 0; i < commands.length; i++) { + command = commands[i].trim(); + cmdLine = new CommandLine(command); + + if (!cmdLine.hasNext()) + continue; + + cmdName = cmdLine.next(); + + try { + cmdInfo = commandShell.getCommandClass(cmdName); + + if (cmdLine.sendToOutFile()) { + File file = new File(cmdLine.getOutFileName()); + + try { + FileOutputStream fileOutputStream = new FileOutputStream( + file); + outputStream = new PrintStream(fileOutputStream); + mustCloseOutputStream = true; + } catch (SecurityException e) { + e.printStackTrace(); + return; // FIXME + } catch (FileNotFoundException e) { + e.printStackTrace(); + return; // FIXME + } + } else if (i + 1 < commands.length) { + byteArrayOutputStream = new ByteArrayOutputStream(); + outputStream = new PrintStream(byteArrayOutputStream); + } else { + outputStream = commandShell.getOutputStream(); + } + + if (byteArrayOutputStream != null) { + nextInputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray()); + } + + if (nextInputStream != null) + inputStream = nextInputStream; + + CommandLine commandLine = null; + + if (inputStream.available() > 0) { + // FIXME we shouldn't do this. It consumes keyboard typeahead + // that should be delivered to the command's standard input!! + commandLine = new CommandLine(inputStream); + } else { + commandLine = cmdLine.getRemainder(); + } + + commandLine.setOutFileName(cmdLine.getOutFileName()); + try { + method = cmdInfo.getCommandClass().getMethod( + EXECUTE_METHOD, EXECUTE_ARG_TYPES); + + cr = createRunner(cmdInfo.getCommandClass(), method, + new Object[] { commandLine, inputStream, + outputStream, errStream }, + inputStream, outputStream, errStream); + } catch (NoSuchMethodException e) { + method = cmdInfo.getCommandClass().getMethod(MAIN_METHOD, + MAIN_ARG_TYPES); + cr = createRunner(cmdInfo.getCommandClass(), method, + new Object[] { cmdLine.getRemainder().toStringArray() }, + commandShell.getInputStream(), commandShell.getOutputStream(), + commandShell.getErrorStream()); + } + try { + if (cmdInfo.isInternal()) { + cr.run(); + } else { + threadProcess = createThread(cr, inputStream, + outputStream, errStream); + threadProcess.start(); + + this.blocking = true; + this.blockingThread = Thread.currentThread(); + while (blocking) { + try { + Thread.sleep(6000); + } catch (InterruptedException interrupted) { + if (!blocking) { + // interruption was okay, break normally. + } else { + // abnormal interruption + interrupted.printStackTrace(); + return; // FIXME + } + } + } + } + } catch (Exception ex) { + err.println("Exception in command"); + ex.printStackTrace(err); + return; // FIXME + } catch (Error ex) { + err.println("Fatal error in command"); + ex.printStackTrace(err); + return; // FIXME + } + } catch (NoSuchMethodException ex) { + err.println("Alias class has no main method " + cmdName); + return; // FIXME + } catch (ClassNotFoundException ex) { + err.println("Unknown alias class " + ex.getMessage()); + return; // FIXME + } catch (ClassCastException ex) { + err.println("Invalid command " + cmdName); + return; // FIXME + } catch (Exception ex) { + err.println("Unknown error: " + ex.getMessage()); + ex.printStackTrace(err); + return; // FIXME + } + finally { + if (mustCloseOutputStream) { + outputStream.close(); + mustCloseOutputStream = false; + } + } + } + + nextInputStream = null; + } + + abstract Thread createThread(Runnable cr, InputStream inputStream, + PrintStream outputStream, PrintStream errStream); + + public void keyPressed(KeyboardEvent ke) { + if (ke.isControlDown() && ke.getKeyCode() == KeyEvent.VK_C) { + doCtrlC(); + } + if (ke.isControlDown() && ke.getKeyCode() == KeyEvent.VK_Z) { + doCtrlZ(); + } + } + + private void doCtrlZ() { + System.err.println("ctrl-z: Returning focus to console. (" + cmdName + + " is still running)"); + unblock(); + } + + @SuppressWarnings("deprecation") + private void doCtrlC() { + System.err.println("ctrl-c: Returning focus to console. (" + cmdName + + " has been killed)"); + + if (threadProcess != null) { + unblock(); + + AccessController.doPrivileged(new PrivilegedAction(){ + public Object run() { + threadProcess.stop(new ThreadDeath()); + return null; + }}); + } + } + + final void unblock() { + blocking = false; + blockingThread.interrupt(); + } + + final boolean isBlocking() { + return blocking; + } + + public void keyReleased(KeyboardEvent event) { + } + + abstract Runnable createRunner(Class cx, Method method, Object[] args, + InputStream commandIn, PrintStream commandOut, PrintStream commandErr); + +} Modified: trunk/shell/src/shell/org/jnode/shell/CommandShell.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -131,6 +131,8 @@ private ThreadCommandInvoker threadCommandInvoker; private DefaultCommandInvoker defaultCommandInvoker; + + private ProcletCommandInvoker procletCommandInvoker; private boolean historyEnabled = true; @@ -148,13 +150,26 @@ } public void setThreadCommandInvoker() { - this.commandInvoker = threadCommandInvoker; + if (this.commandInvoker != threadCommandInvoker) { + err.println("Switched to thread invoker"); + this.commandInvoker = threadCommandInvoker; + } } public void setDefaultCommandInvoker() { - this.commandInvoker = defaultCommandInvoker; + if (this.commandInvoker != defaultCommandInvoker) { + err.println("Switched to default invoker"); + this.commandInvoker = defaultCommandInvoker; + } } + public void setProcletCommandInvoker() { + if (this.commandInvoker != procletCommandInvoker) { + err.println("Switched to proclet invoker"); + this.commandInvoker = procletCommandInvoker; + } + } + /** * Create a new instance * @@ -176,6 +191,7 @@ defaultCommandInvoker = new DefaultCommandInvoker(this); threadCommandInvoker = new ThreadCommandInvoker(this); + procletCommandInvoker = new ProcletCommandInvoker(this); this.commandInvoker = threadCommandInvoker; // default to separate this.console.addConsoleListener(this); // threads for commands. @@ -243,6 +259,18 @@ // Now become interactive while (!isExitted()) { try { + // Temporary mechanism for switching invokers + String invokerName = System.getProperty("jnode.invoker", ""); + if (invokerName.equalsIgnoreCase("default")) { + setDefaultCommandInvoker(); + } + else if (invokerName.equalsIgnoreCase("thread")) { + setThreadCommandInvoker(); + } + else if (invokerName.equalsIgnoreCase("proclet")) { + setProcletCommandInvoker(); + } + clearEof(); out.print(prompt()); readingCommand = true; Added: trunk/shell/src/shell/org/jnode/shell/ProcletCommandInvoker.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/ProcletCommandInvoker.java (rev 0) +++ trunk/shell/src/shell/org/jnode/shell/ProcletCommandInvoker.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -0,0 +1,133 @@ +/* + * $Id: ThreadCommandInvoker.java 3374 2007-08-02 18:15:27Z lsantha $ + * + * JNode.org + * Copyright (C) 2003-2006 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.InputStream; +import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.security.AccessController; +import java.security.PrivilegedActionException; + +import org.jnode.shell.help.Help; +import org.jnode.shell.help.HelpException; +import org.jnode.shell.help.SyntaxErrorException; +import org.jnode.shell.proclet.ProcletContext; +import org.jnode.shell.proclet.ProcletIOContext; +import org.jnode.vm.VmExit; +import org.jnode.vm.VmSystem; + +/** + * User: Sam Reid Date: Dec 20, 2003 Time: 1:20:33 AM Copyright (c) Dec 20, 2003 + * by Sam Reid + * + * @author Sam Reid + * @author Martin Husted Hartvig (ha...@jn...) + * @author cr...@jn... + */ +public class ProcletCommandInvoker extends AsyncCommandInvoker { + + public ProcletCommandInvoker(CommandShell commandShell) { + super(commandShell); + } + + Thread createThread(Runnable cr, InputStream inputStream, + PrintStream outputStream, PrintStream errStream) { + VmSystem.switchToExternalIOContext(new ProcletIOContext()); + return ProcletContext.createProclet( + cr, null, null, + new Object[]{inputStream, outputStream, errStream}, + cmdName); + } + + Runnable createRunner(Class cx, Method method, Object[] args, InputStream commandIn, PrintStream commandOut, PrintStream commandErr) { + return new CommandRunner(cx, method, args); + } + + class CommandRunner implements Runnable { + + private Class cx; + + Method method; + + Object[] args; + + boolean finished = false; + + public CommandRunner(Class cx, Method method, Object[] args) { + this.cx = cx; + this.method = method; + this.args = args; + } + + public void run() { + try { + try { + Object obj = null; + if(!Modifier.isStatic(method.getModifiers())) { + obj = cx.newInstance(); + } + AccessController.doPrivileged(new InvokeAction(method, + obj, args)); + } catch (PrivilegedActionException ex) { + throw ex.getException(); + } + if (!isBlocking()) { + // somebody already hit ctrl-c. + } else { + finished = true; + // System.err.println("Finished invocation, notifying + // blockers."); + // done with invoke, stop waiting for a ctrl-c + unblock(); + } + } catch (InvocationTargetException ex) { + Throwable tex = ex.getTargetException(); + if (tex instanceof SyntaxErrorException) { + try { + Help.getInfo(cx).usage(); + } catch (HelpException ex1) { + // Don't care + ex1.printStackTrace(); + } + err.println(tex.getMessage()); + unblock(); + } else if (tex instanceof VmExit) { + err.println(tex.getMessage()); + unblock(); + } else { + err.println("Exception in command"); + tex.printStackTrace(err); + unblock(); + } + } catch (Exception ex) { + err.println("Exception in command"); + ex.printStackTrace(err); + unblock(); + } + finished = true; + } + } +} Modified: trunk/shell/src/shell/org/jnode/shell/ThreadCommandInvoker.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/ThreadCommandInvoker.java 2007-08-20 20:44:06 UTC (rev 3399) +++ trunk/shell/src/shell/org/jnode/shell/ThreadCommandInvoker.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -23,12 +23,6 @@ import gnu.java.security.action.InvokeAction; -import java.awt.event.KeyEvent; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.InputStream; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; @@ -38,8 +32,6 @@ import java.security.PrivilegedAction; import java.security.PrivilegedActionException; -import org.jnode.driver.input.KeyboardEvent; -import org.jnode.driver.input.KeyboardListener; import org.jnode.shell.help.Help; import org.jnode.shell.help.HelpException; import org.jnode.shell.help.SyntaxErrorException; @@ -48,222 +40,28 @@ /** * User: Sam Reid Date: Dec 20, 2003 Time: 1:20:33 AM Copyright (c) Dec 20, 2003 * by Sam Reid - * + * * @author Sam Reid * @author Martin Husted Hartvig (ha...@jn...) + * @author cr...@jn... */ -public class ThreadCommandInvoker implements CommandInvoker, KeyboardListener { +public class ThreadCommandInvoker extends AsyncCommandInvoker { - PrintStream err; - - CommandShell commandShell; - - private static final Class[] MAIN_ARG_TYPES = new Class[] { String[].class }; - - private static final Class[] EXECUTE_ARG_TYPES = new Class[] { - CommandLine.class, InputStream.class, PrintStream.class, - PrintStream.class }; - - private static final String MAIN_METHOD = "main"; - - private static final String EXECUTE_METHOD = "execute"; - - private boolean blocking; - - private Thread blockingThread; - - private Thread threadProcess = null; - - private String cmdName; - public ThreadCommandInvoker(CommandShell commandShell) { - this.commandShell = commandShell; - this.err = commandShell.getErrorStream(); - commandShell.getConsole().addKeyboardListener(this);// listen for - // ctrl-c + super(commandShell); } + + Thread createThread(Runnable cr, InputStream inputStream, PrintStream outputStream, PrintStream errStream) { + return new Thread(cr, cmdName); + } + + Runnable createRunner(Class cx, Method method, Object[] args, InputStream commandIn, PrintStream commandOut, PrintStream commandErr) { + return new CommandRunner(cx, method, args, commandIn, commandOut, commandErr); + } - public void invoke(String cmdLineStr) { - commandShell.addCommandToHistory(cmdLineStr); - InputStream inputStream = commandShell.getInputStream(); - InputStream nextInputStream = null; - PrintStream errStream = commandShell.getErrorStream(); - PrintStream outputStream = null; - boolean mustCloseOutputStream = false; + class CommandRunner implements Runnable { - CommandLine cmdLine; - Method method; - CommandRunner cr; - CommandInfo cmdInfo; - - String[] commands = cmdLineStr.split("\\|"); - String command; - ByteArrayOutputStream byteArrayOutputStream = null; - - for (int i = 0; i < commands.length; i++) { - command = commands[i].trim(); - cmdLine = new CommandLine(command); - - if (!cmdLine.hasNext()) - continue; - - cmdName = cmdLine.next(); - - try { - cmdInfo = commandShell.getCommandClass(cmdName); - - try { - method = cmdInfo.getCommandClass().getMethod( - EXECUTE_METHOD, EXECUTE_ARG_TYPES); - - if (cmdLine.sendToOutFile()) { - File file = new File(cmdLine.getOutFileName()); - - try { - FileOutputStream fileOutputStream = new FileOutputStream( - file); - outputStream = new PrintStream(fileOutputStream); - mustCloseOutputStream = true; - } catch (SecurityException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } else if (i + 1 < commands.length) { - byteArrayOutputStream = new ByteArrayOutputStream(); - outputStream = new PrintStream(byteArrayOutputStream); - } else { - outputStream = commandShell.getOutputStream(); - } - - if (byteArrayOutputStream != null) { - nextInputStream = new ByteArrayInputStream( - byteArrayOutputStream.toByteArray()); - } - - if (nextInputStream != null) - inputStream = nextInputStream; - - CommandLine commandLine = null; - - if (inputStream.available() > 0) { - // FIXME we shouldn't do this. It consumes keyboard typeahead - // that should be delivered to the command's standard input!! - commandLine = new CommandLine(inputStream); - } else { - commandLine = cmdLine.getRemainder(); - } - - commandLine.setOutFileName(cmdLine.getOutFileName()); - - cr = new CommandRunner(cmdInfo.getCommandClass(), method, - new Object[] { commandLine, inputStream, - outputStream, errStream }, - inputStream, outputStream, errStream); - } catch (NoSuchMethodException e) { - method = cmdInfo.getCommandClass().getMethod(MAIN_METHOD, - MAIN_ARG_TYPES); - cr = new CommandRunner(cmdInfo.getCommandClass(), method, - new Object[] { cmdLine.getRemainder().toStringArray() }, - commandShell.getInputStream(), commandShell.getOutputStream(), - commandShell.getErrorStream()); - } - try { - if (cmdInfo.isInternal()) { - cr.run(); - } else { - threadProcess = new Thread(cr, cmdName); - threadProcess.start(); - - this.blocking = true; - this.blockingThread = Thread.currentThread(); - while (blocking) { - try { - Thread.sleep(6000); - } catch (InterruptedException interrupted) { - if (!blocking) { - // interruption was okay, break normally. - } else { - // abnormal interruption - interrupted.printStackTrace(); - } - } - } - } - } catch (Exception ex) { - err.println("Exception in command"); - ex.printStackTrace(err); - } catch (Error ex) { - err.println("Fatal error in command"); - ex.printStackTrace(err); - } - } catch (NoSuchMethodException ex) { - err.println("Alias class has no main method " + cmdName); - } catch (ClassNotFoundException ex) { - err.println("Unknown alias class " + ex.getMessage()); - } catch (ClassCastException ex) { - err.println("Invalid command " + cmdName); - } catch (Exception ex) { - err.println("Unknown error: " + ex.getMessage()); - ex.printStackTrace(err); - } - finally { - if (mustCloseOutputStream) { - outputStream.close(); - mustCloseOutputStream = false; - } - } - } - - nextInputStream = null; - } - - public void keyPressed(KeyboardEvent ke) { - if (ke.isControlDown() && ke.getKeyCode() == KeyEvent.VK_C) { - doCtrlC(); - } - if (ke.isControlDown() && ke.getKeyCode() == KeyEvent.VK_Z) { - doCtrlZ(); - } - } - - private void doCtrlZ() { - System.err.println("ctrl-z: Returning focus to console. (" + cmdName - + " is still running)"); - unblock(); - } - - @SuppressWarnings("deprecation") - private void doCtrlC() { - System.err.println("ctrl-c: Returning focus to console. (" + cmdName - + " has been killed)"); - - if (threadProcess != null) { - unblock(); - - AccessController.doPrivileged(new PrivilegedAction(){ - public Object run() { - threadProcess.stop(new ThreadDeath()); - return null; - }}); - } - } - - final void unblock() { - blocking = false; - blockingThread.interrupt(); - } - - final boolean isBlocking() { - return blocking; - } - - public void keyReleased(KeyboardEvent event) { - } - - class CommandRunner implements Runnable { - private Class cx; Method method; @@ -342,6 +140,5 @@ } finished = true; } - } } Added: trunk/shell/src/shell/org/jnode/shell/proclet/AbstractProxyPrintStream.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/proclet/AbstractProxyPrintStream.java (rev 0) +++ trunk/shell/src/shell/org/jnode/shell/proclet/AbstractProxyPrintStream.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -0,0 +1,265 @@ +/* + * $Id$ + * + * JNode.org + * Copyright (C) 2003-2007 JNode.org + */ + +/* PrintStream.java -- OutputStream for printing output + Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package org.jnode.shell.proclet; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Locale; +import java.util.Formatter; + +import gnu.classpath.SystemProperties; + + +/** + * This class prints provides infrastructure for PrintStream proxies + */ +public abstract class AbstractProxyPrintStream extends PrintStream +implements ProxyStream<PrintStream> +{ + /* Note: the implementation is mostly copied from PrintStream. Blame this on limitations + * of the afore-mentioned class's specification ... */ + private static PrintStream nullStream; + private static final char[] line_separator = + SystemProperties.getProperty("line.separator", "\n").toCharArray(); + + private boolean error_occurred = false; + + + public AbstractProxyPrintStream() { + super((OutputStream) null); + } + + public boolean checkError() { + flush(); + return error_occurred || effectiveOutput().checkError(); + } + + protected void setError() { + error_occurred = true; + } + + protected abstract PrintStream effectiveOutput(); + + public void close() { + PrintStream eo = effectiveOutput(); + eo.flush(); + eo.close(); + } + + public void flush() { + effectiveOutput().flush(); + } + + protected synchronized void print (String str, boolean println) { + PrintStream eo = effectiveOutput(); + writeChars(eo, str, 0, str.length()); + if (println) { + writeChars(eo, line_separator, 0, line_separator.length); + } + flush(); + } + + protected synchronized void print (char[] chars, int pos, int len, + boolean println) { + PrintStream eo = effectiveOutput(); + writeChars(eo, chars, pos, len); + if (println) { + writeChars(eo, line_separator, 0, line_separator.length); + } + flush(); + } + + protected void writeChars(PrintStream eo, char[] buf, int offset, int count) { + // This is inefficient, but it ensures that we use the encoding + // scheme of the effective stream + eo.print(new String(buf, offset, count)); + } + + protected void writeChars(PrintStream eo, String str, int offset, int count) { + // This is inefficient, but it ensures that we use the encoding + // scheme of the effective stream + eo.print(str.substring(offset, offset + count)); + } + + public void print (boolean bool) { + print(String.valueOf(bool), false); + } + + public void print (int inum) { + print(String.valueOf(inum), false); + } + + public void print (long lnum) { + print(String.valueOf(lnum), false); + } + + public void print (float fnum) { + print(String.valueOf(fnum), false); + } + + public void print (double dnum) { + print(String.valueOf(dnum), false); + } + + public void print (Object obj) { + print(obj == null ? "null" : obj.toString(), false); + } + + public void print (String str) { + print(str == null ? "null" : str, false); + } + + public synchronized void print (char ch) { + print(new char[]{ch}, 0, 1, false); + } + + public void print (char[] charArray) { + print(charArray, 0, charArray.length, false); + } + + public void println() { + print(line_separator, 0, line_separator.length, false); + } + + public void println (boolean bool) { + print(String.valueOf(bool), true); + } + + public void println (int inum) { + print(String.valueOf(inum), true); + } + + public void println (long lnum) { + print(String.valueOf(lnum), true); + } + + public void println (float fnum) { + print(String.valueOf(fnum), true); + } + + public void println (double dnum) { + print(String.valueOf(dnum), true); + } + + public void println (Object obj) { + print(obj == null ? "null" : obj.toString(), true); + } + + public void println (String str) { + print (str == null ? "null" : str, true); + } + + public synchronized void println (char ch) { + print(new char[]{ch}, 0, 1, true); + } + + public void println (char[] charArray) { + print(charArray, 0, charArray.length, true); + } + + public void write (int oneByte) { + effectiveOutput().write (oneByte & 0xff); + if (oneByte == '\n') { + flush(); + } + } + + public void write (byte[] buffer, int offset, int len) { + effectiveOutput().write (buffer, offset, len); + flush(); + } + + public PrintStream append(char c) { + print(c); + return this; + } + + public PrintStream append(CharSequence cs) { + print(cs == null ? "null" : cs.toString()); + return this; + } + + public PrintStream append(CharSequence cs, int start, int end) { + print(cs == null ? "null" : cs.subSequence(start, end).toString()); + return this; + } + + public PrintStream printf(String format, Object... args) { + return format(format, args); + } + + public PrintStream printf(Locale locale, String format, Object... args) { + return format(locale, format, args); + } + + public PrintStream format(String format, Object... args) { + return format(Locale.getDefault(), format, args); + } + + public PrintStream format(Locale locale, String format, Object... args) { + Formatter f = new Formatter(this, locale); + f.format(format, args); + return this; + } + + /** + * Return a print stream that will "deep six" any output. + */ + protected static synchronized PrintStream getNullPrintStream() { + if (nullStream == null) { + nullStream = new PrintStream( + new OutputStream() { + @Override + public void write(int b) throws IOException { + } + }, + false); + } + return nullStream; + } +} Added: trunk/shell/src/shell/org/jnode/shell/proclet/ProcletContext.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/proclet/ProcletContext.java (rev 0) +++ trunk/shell/src/shell/org/jnode/shell/proclet/ProcletContext.java 2007-08-23 20:59:27 UTC (rev 3400) @@ -0,0 +1,307 @@ +package org.jnode.shell.proclet; + +import java.io.Closeable; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import org.jnode.vm.VmSystem; +import org.jnode.vm.VmExit; + + +/** + * This class implements the proclet-specific state used in the JNode proclet mechanism. + * <p> + * A 'proclet' is group of threads that has its own version of the system properties, streams + * and environment and superficially behaves as if it was a self-contained application. + * + * @author cr...@jn... + */ +public class ProcletContext extends ThreadGroup { + private Properties properties; + private Object[] streams; + private Map<String, String> environment; + private int threadCount; + private final int pid; + + private int exitStatus = 0; + private Throwable uncaughtException; + + private static int nextPid = 1; + + private ProcletContext(ThreadGroup parent, Properties properties, + Map<String, String> environment, Object[] streams) + throws ProcletException { + super(parent, nextProcletName()); + ProcletContext parentContext = getParentContext(parent); + if (properties == null) { + if (parentContext != null) { + properties = parentContext.properties; + } + if (properties == null) { + properties = AccessController.doPrivileged( + new PrivilegedAction<Properties>() { + public Properties run() { + return System.getProperties(); + } + }); + } + properties = (Properties) properties.clone(); + } + if (streams == null) { + if (parentContext != null) { + streams = parentContext.streams; + } + if (streams == null) { + try { + streams = new Object[]{ + resolve(System.in), resolve(System.out), resolve(System.err)}; + } + catch (ProxyStreamException ex) { + throw new ProcletException("Broken streams", ex); + } + } + else { + streams = (Object[]) streams.clone(); + } + } + if (environment == null) { + if (parentContext != null) { + environment = new HashMap<String, String>(parentContext.environment); + } + else { + environment = new HashMap<String, String>(); + } + } + this.environment = environment; + this.properties = properties; + this.streams = streams; + this.pid = extractPid(getName()); + } + + private Closeable resolve(Closeable stream) throws ProxyStreamException { + return (stream instanceof ProxyStream) ? + ((ProxyStream) stream).getProxiedStream() : stream; + } + + /** + * Get the proclet's unique PID. This value uniquely identifies the proclet. + * @return the pid + */ + public int getPid() { + return pid; + } + + public synchronized Map<String, String> getEnvironment() { + return environment; + } + + public synchronized Properties getProperties() { + return properties; + } + + /** + * Set the stream object that corresponds to a given 'fd'. + * + * @param fd a non-negative index into the streams vector. + * @param stream the stream object to set. + */ + synchronized void setStream(int fd, Object stream) { + if (stream instanceof ProcletProxyStream) { + throw new IllegalArgumentException("stream is a proclet proxy stream"); + } + if (fd < 0) { + throw new IllegalArgumentException("fd is negative"); + } + if (fd >= streams.length) { + Object[] tmp = new Object[fd + 1]; + System.arraycopy(streams, 0, tmp, 0, streams.length); + streams = tmp; + } + streams[fd] = stream; + } + + /** + * Get the stream object that corresponds to a given 'fd'. + * + * @param fd a non-negative index into the streams vector. + * @return the stream object, or <code>null</code> + */ + public synchronized Object getStream(int fd) { + if (fd < 0) { + throw new IllegalArgumentException("fd is negative"); + } + else if (fd > streams.length) { + return null; + } + else { + return streams[fd]; + } + } + + public synchronized void setProperties(Properties properties) { + this.properties = properties; + } + + /** + * Get the ProcletContext for the current thread. + * + * @return the context, or <code>null</code> if the current thread + * is not a member of a proclet. + */ + public static ProcletContext currentProcletContext() { + if (!VmSystem.hasVmIOContext()) { + return getParentContext(Thread.currentThread().getThreadGroup()); + } + else { + return null; + } + } + + /** + * Get the ProcletContext for a thread group. This is the thread group + * itself, or the innermost enclosing parent thread group that is a + * ProcletContect instance. + * + * @param threadGroup the starting thread group + * @return the context, or <code>null</code> if the thread group does + * not have an ancestor that is a ProcletContex. + */ + private static ProcletContext getParentContext(ThreadGroup threadGroup) { + while (threadGroup != null) { + if (threadGroup instanceof ProcletContext) { + return (ProcletContext) threadGroup; + } + threadGroup = threadGroup.getParent(); + } + return null; + } + + /** + * Create a new Thread as the initial thread for a new proclet. The + * proclet context will be initialised from the current thread's + * proclet context (if it exists) or from {@link java.lang.System#in}, + * {@link java.lang.System#out}, {@link java.lang.System#err}, and + * {@link java.lang.System#getProperties()}. + * + * @param target the new Thread's Runnable object. + * @return the new Thread + */ + public static Thread createProclet(Runnable target) { + return createProclet(target, null, null, null, null, 0); + } + + /** + * Create a new Thread as the initial thread for a new proclet, using a + * supplied set of system properties, and environment and streams vector. + * If any of these is null, the corresponding proclet context will be + * initialised from the current thread's proclet context (if it exists) + * or from {@link java.lang.System#in}, {@link java.lang.System#out}, + * {@link java.lang.System#err}, and {@link java.lang.System#getProperties()}. + * + * @param properties the proclet's system properties, or <code>null</code>. + * @param environment the proclet's environment, or <code>null</code>. + * @param streams the proclet's streams vector, or <code>null</code>. + * @param target the new Thread's Runnable object. + * @return the new Thread + */ + public static Thread createProclet(Runnable target, Properties properties, + Map<String, String> environment, Object[] streams) { + return createProclet(target, properties, environment, streams, null, 0); + } + + /** + * Create a new Thread as the initial thread for a new proclet, using a + * supplied set of system properties, and environment and streams vector. + * If any of these is null, the corresponding proclet context will be + * initialised from the current thread's proclet context (if it exists) + * or from {@link java.lang.System#in}, {@link java.lang.System#out}, + * {@link java.lang.System#err}, and {@link java.lang.System#getProperties()}. + * This overload also supplies an optional thread name. + * + * @param properties the proclet's system properties, or <code>null</code>. + * @param environment the proclet's environment, or <code>null</code>. + * @param streams the proclet's streams vector, or <code>null</code>. + * @param target the new Thread's Runnable object. + * @param name an optional Thread name. + * @return the new Thread + */ + public static Thread createProclet(Runnable target, Properties properties, + Map<String, String> environment, Object[] streams, String name) { + return... [truncated message content] |