|
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] |