added a factory method to LuaState to dynamically create LuaState or DebugLuaState depending on the presence of the platform debug properties

This commit is contained in:
Shu Lei
2007-11-30 23:47:44 +00:00
parent 0db9925ee9
commit 96864694de
5 changed files with 203 additions and 93 deletions

View File

@@ -70,6 +70,9 @@ import org.luaj.lib.TableLib;
*/
public class LuaState extends Lua {
public static final String PROPERTY_LUAJ_DEBUG = "Luaj-Debug";
protected static final String DEBUG_CLASS_NAME = "org.luaj.debug.DebugLuaState";
/* thread status; 0 is OK */
private static final int LUA_YIELD = 1;
private static final int LUA_ERRRUN = 2;
@@ -109,6 +112,8 @@ public class LuaState extends Lua {
* does all memory allocation for this state through this function. The
* second argument, <code>ud</code>, is an opaque pointer that Lua simply
* passes to the allocator in every call.
*
* @deprecated As of version 0.10, replaced by {@link #newState()}
*/
public LuaState() {
_G = new LTable();
@@ -119,6 +124,38 @@ public class LuaState extends Lua {
_G = globals;
}
/**
* Factory method to return an instance of LuaState. If debug property is
* present, it will create a DebugLuaState instance.
* @return
*/
public static LuaState newState() {
String isDebugStr
= Platform.getInstance().getProperty(PROPERTY_LUAJ_DEBUG, "false");
boolean isDebug = Boolean.parseBoolean(isDebugStr);
LuaState vm = null;
if ( isDebug ) {
try {
vm = (LuaState) Class.forName( DEBUG_CLASS_NAME ).newInstance();
} catch (Exception e) {
System.out.println("Warning: no debug support, " + e );
}
}
if ( vm == null )
vm = new LuaState();
vm.init();
return vm;
}
/**
* Performs the initialization.
*/
public void init() {}
/**
* Install the standard set of libraries used by most implementations:
* BaseLib, CoroutineLib, MathLib, PackageLib, TableLib, StringLib

View File

@@ -21,10 +21,15 @@
******************************************************************************/
package org.luaj.vm;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import org.luaj.debug.DebugLuaState;
import org.luaj.debug.net.DebugSupport;
import org.luaj.debug.net.j2se.DebugSupportImpl;
/**
* Singleton to manage platform-specific behaviors.
*
@@ -41,18 +46,40 @@ abstract public class Platform {
* InputStreamReader class.
*/
public static Platform getInstance() {
if ( instance == null ) {
instance = new Platform() {
public Reader createReader(InputStream inputStream) {
return new InputStreamReader(inputStream);
}
public InputStream openFile(String fileName) {
return getClass().getResourceAsStream("/"+fileName);
}
};
}
return instance;
}
if (instance == null) {
instance = new Platform() {
public Reader createReader(InputStream inputStream) {
return new InputStreamReader(inputStream);
}
public InputStream openFile(String fileName) {
return getClass().getResourceAsStream("/" + fileName);
}
/**
* Assumes J2SE platform, return the corresponding system property
*/
public String getProperty(String propertyName,
String defaultValue) {
return System.getProperty(propertyName, defaultValue);
}
/**
* Provides a J2SE DebugSupport instance.
*/
public DebugSupport getDebugSupport() throws IOException {
String portStr = getProperty(DebugLuaState.PROPERTY_LUAJ_DEBUG_PORT, "-1");
try {
int port = Integer.parseInt(portStr);
return new DebugSupportImpl(port);
} catch (NumberFormatException e) {
throw new IOException("Bad port number: " + portStr);
}
}
};
}
return instance;
}
/**
* Set the Platform instance.
@@ -77,4 +104,18 @@ abstract public class Platform {
* @return Reader instance to use for character input
*/
abstract public Reader createReader( InputStream inputStream );
/**
* Returns the value for the given platform property.
* @param propertyName Property name
* @param defaultValue Default property value
* @return Property value
*/
abstract public String getProperty(String propertyName, String defaultValue);
/**
* Returns an platform dependent DebugSupport instance.
* @return an plaform dependent DebugSupport instance.
*/
abstract public DebugSupport getDebugSupport() throws IOException;
}

View File

@@ -45,9 +45,14 @@ import org.luaj.vm.LocVars;
import org.luaj.vm.Lua;
import org.luaj.vm.LuaErrorException;
import org.luaj.vm.LuaState;
import org.luaj.vm.Platform;
public class DebugLuaState extends LuaState implements DebugRequestListener {
public static final String PROPERTY_LUAJ_DEBUG_SUSPEND_AT_START = "Luaj-Debug-SuspendAtStart";
public static final String PROPERTY_LUAJ_DEBUG_HOST = "Luaj-Debug-Host";
public static final String PROPERTY_LUAJ_DEBUG_PORT = "Luaj-Debug-Port";
private static final boolean TRACE = (null != System.getProperty("TRACE"));
// stepping constants and stepping state
@@ -68,9 +73,35 @@ public class DebugLuaState extends LuaState implements DebugRequestListener {
protected DebugSupport debugSupport;
protected LuaErrorException lastError;
/**
* Creates an instance of DebugLuaState.
*
* @deprecated As of version 0.10, replaced by {@link #LuaState.newState()}
*/
public DebugLuaState() {}
public void setDebugSupport(DebugSupport debugSupport)
public void init() {
Platform platform = Platform.getInstance();
// set if the vm should be suspended at start
String suspendOnStartStr = platform.getProperty(PROPERTY_LUAJ_DEBUG_SUSPEND_AT_START, "false");
boolean bSuspendOnStart = Boolean.parseBoolean(suspendOnStartStr);
setSuspendAtStart(bSuspendOnStart);
// set up the debug networking support
try {
DebugSupport debugSupport = platform.getDebugSupport();
if (debugSupport != null)
setDebugSupport(debugSupport);
else
System.out.println("Warning: DebugSupport is not implemented.");
} catch (IOException e) {
// no debug client can talk to VM, but VM can continue functioning
System.out.println("Warning: no debug client support due to error: " + e.getMessage());
}
}
protected void setDebugSupport(DebugSupport debugSupport)
throws IOException {
if (debugSupport == null) {
throw new IllegalArgumentException("DebugSupport cannot be null");
@@ -394,16 +425,17 @@ public class DebugLuaState extends LuaState implements DebugRequestListener {
synchronized (this) {
if (exiting) return;
if (this.debugSupport == null) {
throw new IllegalStateException(
"DebugSupport must be defined.");
if (this.debugSupport != null) {
DebugMessage event = new DebugMessage(DebugMessageType.terminated);
debugSupport.notifyDebugEvent(event);
}
DebugMessage event = new DebugMessage(DebugMessageType.terminated);
debugSupport.notifyDebugEvent(event);
exit();
debugSupport.stop();
debugSupport = null;
if (this.debugSupport != null) {
debugSupport.stop();
debugSupport = null;
}
}
}

View File

@@ -28,8 +28,6 @@ import java.io.InputStream;
import org.luaj.compiler.LuaC;
import org.luaj.debug.DebugLuaState;
import org.luaj.debug.net.DebugSupport;
import org.luaj.debug.net.j2se.DebugSupportImpl;
import org.luaj.lib.j2se.LuajavaLib;
import org.luaj.vm.LClosure;
import org.luaj.vm.LPrototype;
@@ -81,8 +79,10 @@ public class StandardLuaJVM {
if (args.length < 2) {
throw new ParseException("Invalid command line arguments.");
}
this.isDebugMode = true;
System.setProperty(LuaState.PROPERTY_LUAJ_DEBUG, "true");
String debugOptions = args[0];
debugOptions = debugOptions.substring(2); // remove '-D'
String[] options = debugOptions.split(",");
@@ -91,6 +91,7 @@ public class StandardLuaJVM {
String portString = options[i].substring(CMD_LINE_DEBUG_OPTION_PORT.length());
try {
this.debugPort = Integer.parseInt(portString);
System.setProperty(DebugLuaState.PROPERTY_LUAJ_DEBUG_PORT, String.valueOf(debugPort));
if (this.debugPort <= 0) {
throw new ParseException(
"Invalid debug port: it must be greater than zero.");
@@ -105,12 +106,13 @@ public class StandardLuaJVM {
!suspendOnStartStr.equalsIgnoreCase("false")) {
throw new ParseException("invalid debug flag: suspendOnStart");
}
this.bSuspendOnStart = Boolean.valueOf(suspendOnStartStr).booleanValue();
this.bSuspendOnStart = Boolean.parseBoolean(suspendOnStartStr);
System.setProperty(DebugLuaState.PROPERTY_LUAJ_DEBUG_SUSPEND_AT_START, suspendOnStartStr);
} else {
throw new ParseException("Invalid command line argument: " + debugOptions);
}
}
if (this.debugPort == -1) {
throw new ParseException("Invalid command line: debug port is missing");
}
@@ -168,10 +170,28 @@ public class StandardLuaJVM {
public void run() {
try {
if (isDebug()) {
doDebug();
} else {
doRun();
// new lua debug state
state = LuaState.newState();
init(state);
// load the Lua file
InputStream is = new FileInputStream(new File(getScript()));
LPrototype p = LoadState.undump(state, is, getScript());
// create closure and execute
final LClosure c = new LClosure(p, state._G);
String[] args = getScriptArgs();
int numOfScriptArgs = (args != null ? args.length : 0);
LValue[] vargs = new LValue[numOfScriptArgs];
for (int i = 0; i < numOfScriptArgs; i++) {
vargs[i] = new LString(args[i]);
}
try {
state.doCall(c, vargs);
} finally {
if (state instanceof DebugLuaState) {
((DebugLuaState)state).stop();
}
}
} catch (LuaErrorException e) {
System.err.println("Error: " + e.getMessage());
@@ -194,62 +214,6 @@ public class StandardLuaJVM {
LuaC.install();
}
protected void doRun() throws IOException {
// new lua state
state = new LuaState();
init(state);
// convert args to lua
String[] scriptArgs = getScriptArgs();
int numOfScriptArgs = (scriptArgs == null) ? 0 : scriptArgs.length;
LValue[] vargs = new LValue[numOfScriptArgs];
for (int i = 0; i < numOfScriptArgs; i++) {
vargs[i] = new LString(getScriptArgs()[i]);
}
// load the Lua file
InputStream is = new FileInputStream(new File(getScript()));
LPrototype p = LoadState.undump(state, is, getScript());
// create closure and execute
LClosure c = new LClosure(state, p);
state.doCall(c, vargs);
}
protected void doDebug() throws IOException {
// new lua debug state
state = new DebugLuaState();
init(state);
// load the Lua file
InputStream is = new FileInputStream(new File(getScript()));
LPrototype p = LoadState.undump(state, is, getScript());
// set up debug support if the file is successfully loaded
DebugSupport debugSupport = new DebugSupportImpl(getDebugPort());
getDebugState().setSuspendAtStart(getSuspendOnStart());
getDebugState().setDebugSupport(debugSupport);
// create closure and execute
final LClosure c = new LClosure(p, state._G);
String[] args = getScriptArgs();
int numOfScriptArgs = (args != null ? args.length : 0);
LValue[] vargs = new LValue[numOfScriptArgs];
for (int i = 0; i < numOfScriptArgs; i++) {
vargs[i] = new LString(args[i]);
}
try {
getDebugState().doCall(c, vargs);
} finally {
getDebugState().stop();
}
}
private DebugLuaState getDebugState() {
return (DebugLuaState) state;
}
/**
* Parses the command line arguments and executes/debugs the lua program.
* @param args -- command line arguments:

View File

@@ -21,14 +21,15 @@
******************************************************************************/
package org.luaj.debug.j2se;
import java.io.IOException;
import java.net.URL;
import org.luaj.debug.j2se.StandardLuaJVM;
import org.luaj.debug.j2se.StandardLuaJVM.ParseException;
import java.util.Properties;
import junit.framework.TestCase;
import org.luaj.debug.DebugLuaState;
import org.luaj.debug.j2se.StandardLuaJVM.ParseException;
import org.luaj.vm.LuaState;
/**
* Sanity test for StandardLuaJVM.
*/
@@ -88,7 +89,7 @@ public class LuaJVMTest extends TestCase {
vm = new StandardLuaJVM();
try {
vm.parse(args);
assertFalse(1044 == vm.getDebugPort());
assertTrue(1044 == vm.getDebugPort());
assertFalse(true == vm.getSuspendOnStart());
assertEquals("dummy.lua", vm.getScript());
} catch (ParseException e) {
@@ -133,7 +134,18 @@ public class LuaJVMTest extends TestCase {
} catch (ParseException e) {
fail("Should never reach this line.");
}
args = new String[] { "-Dport=1044,suspendOnStart=True", "dummy.lua" };
vm = new StandardLuaJVM();
try {
vm.parse(args);
assertEquals(1044, vm.getDebugPort());
assertEquals(true, vm.getSuspendOnStart());
assertEquals("dummy.lua", vm.getScript());
} catch (ParseException e) {
fail("Should never reach this line.");
}
args = new String[] { "-DsuspendOnStart=true,port=1044", "dummy.lua" };
vm = new StandardLuaJVM();
try {
@@ -169,13 +181,37 @@ public class LuaJVMTest extends TestCase {
}
public void testRun() {
Properties props = System.getProperties();
props.remove(LuaState.PROPERTY_LUAJ_DEBUG);
props.remove(DebugLuaState.PROPERTY_LUAJ_DEBUG_HOST);
props.remove(DebugLuaState.PROPERTY_LUAJ_DEBUG_PORT);
props.remove(DebugLuaState.PROPERTY_LUAJ_DEBUG_SUSPEND_AT_START);
System.setProperties(props);
String[] tests = new String[] { "autoload", "boolean", "calls",
"coercions", "compare", "math", "mathlib", "metatables",
"select", "setlist", "swingapp", "test1", "test2", "test3",
"test4", "test5", "test6", "test7", "type", "upvalues",
// "strlib"
"strlib"
};
doRun(tests);
}
public void testDebugRun() {
Properties props = System.getProperties();
props.setProperty(LuaState.PROPERTY_LUAJ_DEBUG, "true");
props.setProperty(DebugLuaState.PROPERTY_LUAJ_DEBUG_PORT, "1999");
System.setProperties(props);
String[] tests = new String[] { "boolean", "calls",
"coercions", "compare", "math", "mathlib", "metatables",
"select", "setlist", "swingapp", "test1", "test2", "test3",
"test4", "test5", "test6", "test7", "type", "upvalues"
};
doRun(tests);
}
private void doRun(String[] tests) {
for (int i = 0; i < tests.length; i++) {
String test = tests[i];
System.out.println("==> running test: " + test + ".lua");
@@ -185,7 +221,7 @@ public class LuaJVMTest extends TestCase {
System.out.println();
}
}
protected void doTestRun(String testName) {
String[] args = new String[1];
URL filePath = getClass().getResource("/" + testName);