diff --git a/.classpath b/.classpath
index fc39bf58..1af1087a 100644
--- a/.classpath
+++ b/.classpath
@@ -6,5 +6,6 @@
+
diff --git a/build.xml b/build.xml
index 11145062..c17a9eee 100644
--- a/build.xml
+++ b/build.xml
@@ -13,8 +13,9 @@
-
-
+
+
+
diff --git a/src/main/java/lua/debug/DebugStackState.java b/src/main/java/lua/debug/DebugStackState.java
index 4d3d486a..66af7c4a 100644
--- a/src/main/java/lua/debug/DebugStackState.java
+++ b/src/main/java/lua/debug/DebugStackState.java
@@ -21,7 +21,10 @@
******************************************************************************/
package lua.debug;
+import java.io.IOException;
import java.util.Hashtable;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.Vector;
import lua.CallInfo;
@@ -30,7 +33,7 @@ import lua.StackState;
import lua.addon.compile.LexState;
import lua.debug.event.DebugEvent;
import lua.debug.event.DebugEventBreakpoint;
-import lua.debug.event.DebugEventListener;
+import lua.debug.event.DebugEventType;
import lua.debug.request.DebugRequest;
import lua.debug.request.DebugRequestLineBreakpointToggle;
import lua.debug.request.DebugRequestListener;
@@ -40,6 +43,7 @@ import lua.debug.response.DebugResponse;
import lua.debug.response.DebugResponseCallgraph;
import lua.debug.response.DebugResponseSimple;
import lua.debug.response.DebugResponseStack;
+import lua.io.Closure;
import lua.io.LocVars;
import lua.io.Proto;
import lua.value.LTable;
@@ -54,34 +58,24 @@ public class DebugStackState extends StackState implements DebugRequestListener
protected boolean suspended = false;
protected boolean stepping = false;
protected int lastline = -1;
- protected Vector debugEventListeners = new Vector();
+ protected DebugSupport debugSupport = null;
+
+ public DebugStackState() {}
- public DebugStackState() {
+ public void setDebugSupport(DebugSupport debugSupport) throws IOException {
+ if (debugSupport == null) {
+ throw new IllegalArgumentException("DebugSupport cannot be null");
+ }
+
+ this.debugSupport = debugSupport;
+ debugSupport.setDebugStackState(this);
+ debugSupport.start();
}
protected void debugAssert(boolean b) {
if ( ! b )
error( "assert failure" );
}
-
- public void addDebugEventListener(DebugEventListener listener) {
- if (!debugEventListeners.contains(listener)) {
- debugEventListeners.addElement(listener);
- }
- }
-
- public void removeDebugEventListener(DebugEventListener listener) {
- if (debugEventListeners.contains(listener)) {
- debugEventListeners.removeElement(listener);
- }
- }
-
- protected void notifyDebugEventListeners(DebugEvent event) {
- for (int i = 0; debugEventListeners != null && i < debugEventListeners.size(); i++) {
- DebugEventListener listener = (DebugEventListener)debugEventListeners.elementAt(i);
- listener.notifyDebugEvent(event);
- }
- }
private String getFileLine(int cindex) {
String func = "?";
@@ -157,10 +151,12 @@ public class DebugStackState extends StackState implements DebugRequestListener
Proto p = calls[cc].closure.p;
String source = DebugUtils.getSourceFileName(p.source);
if ( breakpoints.containsKey(constructBreakpointKey(source, line))){
- if(DebugUtils.IS_DEBUG)
+ if(DebugUtils.IS_DEBUG) {
DebugUtils.println("hitting breakpoint " + constructBreakpointKey(source, line));
- notifyDebugEventListeners(
- new DebugEventBreakpoint(source, line));
+ }
+ if (debugSupport != null) {
+ debugSupport.notifyDebugEvent(new DebugEventBreakpoint(source, line));
+ }
suspended = true;
} else {
return;
@@ -195,16 +191,28 @@ public class DebugStackState extends StackState implements DebugRequestListener
// ------------------ commands coming from the debugger -------------------
public DebugResponse handleRequest(DebugRequest request) {
+ if (this.debugSupport == null) {
+ throw new IllegalStateException("DebugStackState is not equiped with DebugSupport.");
+ }
+
DebugUtils.println("DebugStackState is handling request: " + request.toString());
- DebugRequestType requestType = request.getType();
- if (DebugRequestType.suspend == requestType) {
- suspend();
+ DebugRequestType requestType = request.getType();
+ if (DebugRequestType.start == requestType) {
+ DebugEvent event = new DebugEvent(DebugEventType.started);
+ debugSupport.notifyDebugEvent(event);
+ return DebugResponseSimple.SUCCESS;
+ } else if (DebugRequestType.exit == requestType) {
+ stop();
+ return DebugResponseSimple.SUCCESS;
+ } else if (DebugRequestType.suspend == requestType) {
+ suspend();
+ DebugEvent event = new DebugEvent(DebugEventType.suspendedByClient);
+ debugSupport.notifyDebugEvent(event);
return DebugResponseSimple.SUCCESS;
} else if (DebugRequestType.resume == requestType) {
- resume();
- return DebugResponseSimple.SUCCESS;
- } else if (DebugRequestType.exit == requestType) {
- exit();
+ resume();
+ DebugEvent event = new DebugEvent(DebugEventType.resumedByClient);
+ debugSupport.notifyDebugEvent(event);
return DebugResponseSimple.SUCCESS;
} else if (DebugRequestType.lineBreakpointSet == requestType) {
DebugRequestLineBreakpointToggle setBreakpointRequest
@@ -252,7 +260,25 @@ public class DebugStackState extends StackState implements DebugRequestListener
this.notify();
}
}
-
+
+ public void stop() {
+ if (this.debugSupport == null) {
+ throw new IllegalStateException("DebugStackState is not equiped with DebugSupport.");
+ }
+
+ DebugEvent event = new DebugEvent(DebugEventType.terminated);
+ debugSupport.notifyDebugEvent(event);
+
+ new Timer().schedule(new TimerTask() {
+ public void run () {
+ debugSupport.stop();
+ debugSupport = null;
+ }
+ }, 300);
+
+ exit();
+ }
+
/**
* terminate the execution
*/
diff --git a/src/main/java/lua/debug/DebugSupport.java b/src/main/java/lua/debug/DebugSupport.java
new file mode 100644
index 00000000..8903a8f7
--- /dev/null
+++ b/src/main/java/lua/debug/DebugSupport.java
@@ -0,0 +1,198 @@
+package lua.debug;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+
+import lua.debug.event.DebugEvent;
+import lua.debug.event.DebugEventListener;
+import lua.debug.request.DebugRequest;
+import lua.debug.request.DebugRequestListener;
+import lua.debug.response.DebugResponse;
+
+public class DebugSupport implements DebugRequestListener, DebugEventListener {
+ protected static final int UNKNOWN = 0;
+ protected static final int RUNNING = 1;
+ protected static final int STOPPED = 2;
+
+ protected DebugStackState vm;
+ protected int requestPort;
+ protected int eventPort;
+ protected Thread requestWatcherThread;
+ protected int state = UNKNOWN;
+
+ protected DataInputStream requestReader;
+ protected DataOutputStream requestWriter;
+ protected DataOutputStream eventWriter;
+
+ public DebugSupport(int requestPort,
+ int eventPort) {
+ if (requestPort == -1) {
+ throw new IllegalArgumentException("requestPort is invalid");
+ }
+
+ if (eventPort == -1) {
+ throw new IllegalArgumentException("eventPort is invalid");
+ }
+
+ this.requestPort = requestPort;
+ this.eventPort = eventPort;
+ }
+
+ public void setDebugStackState(DebugStackState vm) {
+ this.vm = vm;
+ }
+
+ protected void releaseServer() {
+ DebugUtils.println("shutting down the debug server...");
+ if (requestReader != null) {
+ try {
+ requestReader.close();
+ } catch (IOException e) {}
+ }
+
+ if (requestWriter != null) {
+ try {
+ requestWriter.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (eventWriter != null) {
+ try {
+ eventWriter.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public synchronized boolean isStarted() {
+ return (state == RUNNING || state == STOPPED);
+ }
+
+ /* (non-Javadoc)
+ * @see lua.debug.j2se.DebugSupport#start()
+ */
+ public synchronized void start() throws IOException {
+ if (this.vm == null) {
+ throw new IllegalStateException("DebugStackState is not set. Please call setDebugStackState first.");
+ }
+
+ this.requestWatcherThread = new Thread(new Runnable() {
+ public void run() {
+ if (getState() != STOPPED) {
+ handleRequest();
+ } else {
+ releaseServer();
+ }
+ }
+ });
+ this.requestWatcherThread.start();
+ this.state = RUNNING;
+
+ System.out.println("LuaJ debug server is started on ports: " + requestPort + ", " + eventPort);
+ }
+
+ protected synchronized int getState() {
+ return this.state;
+ }
+
+ /* (non-Javadoc)
+ * @see lua.debug.j2se.DebugSupport#stop()
+ */
+ public synchronized void stop() {
+ DebugUtils.println("stopping the debug support...");
+ this.state = STOPPED;
+ }
+
+ protected void handleRequest() {
+ try {
+ while (getState() != STOPPED) {
+ int size = requestReader.readInt();
+ byte[] data = new byte[size];
+ requestReader.readFully(data);
+ DebugRequest request
+ = (DebugRequest) SerializationHelper.deserialize(data);
+ DebugUtils.println("SERVER receives request: " + request.toString());
+
+ DebugResponse response = handleRequest(request);
+ data = SerializationHelper.serialize(response);
+ requestWriter.writeInt(data.length);
+ requestWriter.write(data);
+ requestWriter.flush();
+ DebugUtils.println("SERVER sends response: " + response);
+ }
+
+ if (getState() == STOPPED) {
+ cleanup();
+ }
+ } catch (EOFException e) {
+ cleanup();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void cleanup() {
+ DebugUtils.println("SERVER terminated...");
+ releaseServer();
+ System.exit(0);
+ }
+
+ /**
+ * This method provides the second communication channel with the debugging
+ * client. The server can send events via this channel to notify the client
+ * about debug events (see below) asynchronously.
+ *
+ * The following events can be fired:
+ * 1. started -- the vm is started and ready to receive debugging requests
+ * (guaranteed to be the first event sent)
+ * 2. terminated -- the vm is terminated (guaranteed to be the last event sent)
+ * 3. suspended client|step|breakpoint N
+ * -- the vm is suspended by client, due to a stepping request or
+ * the breakpoint at line N is hit
+ * 4. resumed client|step
+ * -- the vm resumes execution by client or step
+ *
+ * @param event
+ */
+ protected void sendEvent(DebugEvent event) {
+ DebugUtils.println("SERVER sending event: " + event.toString());
+ try {
+ byte[] data = SerializationHelper.serialize(event);
+ eventWriter.writeInt(data.length);
+ eventWriter.write(data);
+ eventWriter.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see lua.debug.DebugEventListener#notifyDebugEvent(lua.debug.DebugEvent)
+ */
+ /* (non-Javadoc)
+ * @see lua.debug.j2se.DebugSupport#notifyDebugEvent(lua.debug.event.DebugEvent)
+ */
+ public void notifyDebugEvent(DebugEvent event) {
+ sendEvent(event);
+ }
+
+ /* (non-Javadoc)
+ * @see lua.debug.DebugRequestListener#handleRequest(java.lang.String)
+ */
+ /* (non-Javadoc)
+ * @see lua.debug.j2se.DebugSupport#handleRequest(lua.debug.request.DebugRequest)
+ */
+ public DebugResponse handleRequest(DebugRequest request) {
+ if (DebugUtils.IS_DEBUG) {
+ DebugUtils.println("handling request: " + request.toString());
+ }
+
+ DebugResponse response = vm.handleRequest(request);
+ return response;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/lua/debug/j2me/DebugSupportImpl.java b/src/main/java/lua/debug/j2me/DebugSupportImpl.java
new file mode 100644
index 00000000..e7b92a0c
--- /dev/null
+++ b/src/main/java/lua/debug/j2me/DebugSupportImpl.java
@@ -0,0 +1,98 @@
+package lua.debug.j2me;
+
+import java.io.IOException;
+
+import javax.microedition.io.Connector;
+import javax.microedition.io.ServerSocketConnection;
+import javax.microedition.io.SocketConnection;
+
+import lua.debug.DebugSupport;
+import lua.debug.DebugUtils;
+import lua.debug.event.DebugEvent;
+
+public class DebugSupportImpl extends DebugSupport {
+ protected ServerSocketConnection requestServerConnection;
+ protected SocketConnection requestSocketConnection;
+
+ protected ServerSocketConnection eventServerConnection;
+ protected SocketConnection eventSocketConnection;
+
+ public DebugSupportImpl(int requestPort,
+ int eventPort) {
+ super(requestPort, eventPort);
+ }
+
+ /* (non-Javadoc)
+ * @see lua.debug.j2se.DebugSupport#start()
+ */
+ public synchronized void start() throws IOException {
+ System.out.println("Starting the sockets....");
+ // Set up the request socket and request input + output streams
+ this.requestServerConnection
+ = (ServerSocketConnection)Connector.open("socket://:" + this.requestPort);
+ this.requestSocketConnection =
+ (SocketConnection) requestServerConnection.acceptAndOpen();
+ requestSocketConnection.setSocketOption(SocketConnection.DELAY, 0);
+ requestSocketConnection.setSocketOption(SocketConnection.LINGER, 0);
+ requestSocketConnection.setSocketOption(SocketConnection.KEEPALIVE, 1);
+ requestSocketConnection.setSocketOption(SocketConnection.RCVBUF, 1024);
+ requestSocketConnection.setSocketOption(SocketConnection.SNDBUF, 1024);
+ this.requestReader = requestSocketConnection.openDataInputStream();
+ this.requestWriter = requestSocketConnection.openDataOutputStream();
+
+ // Set up the event socket and event output stream
+ this.eventServerConnection
+ = (ServerSocketConnection)Connector.open("socket://:" + this.eventPort);
+ this.eventSocketConnection
+ = (SocketConnection) eventServerConnection.acceptAndOpen();
+ eventSocketConnection.setSocketOption(SocketConnection.DELAY, 0);
+ eventSocketConnection.setSocketOption(SocketConnection.LINGER, 0);
+ eventSocketConnection.setSocketOption(SocketConnection.KEEPALIVE, 1);
+ eventSocketConnection.setSocketOption(SocketConnection.RCVBUF, 1024);
+ eventSocketConnection.setSocketOption(SocketConnection.SNDBUF, 1024);
+ this.eventWriter = eventSocketConnection.openDataOutputStream();;
+
+ System.out.println("Lua debug server is started on ports: " + requestPort + ", " + eventPort);
+ super.start();
+ }
+
+ protected void releaseServer() {
+ super.releaseServer();
+
+ if (requestSocketConnection != null) {
+ try {
+ requestSocketConnection.close();
+ } catch (IOException e) {}
+ }
+
+ if (requestServerConnection != null) {
+ try {
+ requestServerConnection.close();
+ } catch (IOException e) {}
+ }
+
+ if (eventSocketConnection != null) {
+ try {
+ eventSocketConnection.close();
+ } catch (IOException e) {}
+ }
+
+ if (eventServerConnection != null){
+ try {
+ eventServerConnection.close();
+ } catch (IOException e) {}
+ }
+ }
+
+ protected void handleRequest() {
+ synchronized (requestSocketConnection) {
+ super.handleRequest();
+ }
+ }
+
+ protected void sendEvent(DebugEvent event) {
+ synchronized (eventSocketConnection) {
+ super.sendEvent(event);
+ }
+ }
+}
diff --git a/src/main/java/lua/debug/j2se/DebugSupport.java b/src/main/java/lua/debug/j2se/DebugSupport.java
deleted file mode 100644
index daafd58e..00000000
--- a/src/main/java/lua/debug/j2se/DebugSupport.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*******************************************************************************
-* Copyright (c) 2007 LuaJ. All rights reserved.
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-******************************************************************************/
-package lua.debug.j2se;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.Socket;
-
-import lua.debug.DebugUtils;
-import lua.debug.SerializationHelper;
-import lua.debug.event.DebugEvent;
-import lua.debug.event.DebugEventListener;
-import lua.debug.request.DebugRequest;
-import lua.debug.request.DebugRequestListener;
-import lua.debug.response.DebugResponse;
-
-public class DebugSupport implements DebugRequestListener, DebugEventListener {
- protected static final int UNKNOWN = 0;
- protected static final int RUNNING = 1;
- protected static final int STOPPED = 2;
-
- protected DebugRequestListener vm;
- protected int requestPort;
- protected int eventPort;
- protected Thread requestWatcherThread;
- protected int state = UNKNOWN;
-
- protected ServerSocket requestSocket;
- protected Socket clientRequestSocket;
- protected DataInputStream requestReader;
- protected DataOutputStream requestWriter;
-
- protected ServerSocket eventSocket;
- protected Socket clientEventSocket;
- protected DataOutputStream eventWriter;
-
- public DebugSupport(DebugRequestListener vm,
- int requestPort,
- int eventPort) {
- this.vm = vm;
- this.requestPort = requestPort;
- this.eventPort = eventPort;
- }
-
- protected void releaseServer() {
- DebugUtils.println("shutting down the debug server...");
- if (requestReader != null) {
- try {
- requestReader.close();
- } catch (IOException e) {}
- }
-
- if (requestWriter != null) {
- try {
- requestWriter.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- if (clientRequestSocket != null) {
- try {
- clientRequestSocket.close();
- } catch (IOException e) {}
- }
-
- if (requestSocket != null) {
- try {
- requestSocket.close();
- } catch (IOException e) {}
- }
-
- if (eventWriter != null) {
- try {
- eventWriter.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- if (clientEventSocket != null) {
- try {
- clientEventSocket.close();
- } catch (IOException e) {}
- }
-
- if (eventSocket != null){
- try {
- eventSocket.close();
- } catch (IOException e) {}
- }
- }
-
- public synchronized void start() throws IOException {
- this.requestSocket = new ServerSocket(requestPort);
- this.clientRequestSocket = requestSocket.accept();
- this.requestReader
- = new DataInputStream(clientRequestSocket.getInputStream());
- this.requestWriter
- = new DataOutputStream(clientRequestSocket.getOutputStream());
-
- this.eventSocket = new ServerSocket(eventPort);
- this.clientEventSocket = eventSocket.accept();
- this.eventWriter
- = new DataOutputStream(clientEventSocket.getOutputStream());
-
- this.requestWatcherThread = new Thread(new Runnable() {
- public void run() {
- if (getState() != STOPPED) {
- handleRequest();
- } else {
- releaseServer();
- }
- }
- });
- this.requestWatcherThread.start();
- this.state = RUNNING;
- }
-
- protected synchronized int getState() {
- return this.state;
- }
-
- public synchronized void stop() {
- this.state = STOPPED;
- }
-
- protected void handleRequest() {
- synchronized (clientRequestSocket) {
- try {
- while (getState() != STOPPED) {
- int size = requestReader.readInt();
- byte[] data = new byte[size];
- requestReader.readFully(data);
- DebugRequest request
- = (DebugRequest) SerializationHelper.deserialize(data);
- DebugUtils.println("SERVER receives request: " + request.toString());
-
- DebugResponse response = handleRequest(request);
- data = SerializationHelper.serialize(response);
- requestWriter.writeInt(data.length);
- requestWriter.write(data);
- requestWriter.flush();
- DebugUtils.println("SERVER sends response: " + response);
- }
-
- if (getState() == STOPPED) {
- cleanup();
- }
- } catch (EOFException e) {
- cleanup();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- /**
- *
- */
- private void cleanup() {
- DebugUtils.println("SERVER terminated...");
- releaseServer();
- System.exit(0);
- }
-
- /**
- * This method provides the second communication channel with the debugging
- * client. The server can send events via this channel to notify the client
- * about debug events (see below) asynchonously.
- *
- * The following events can be fired:
- * 1. started -- the vm is started and ready to receive debugging requests
- * (guaranteed to be the first event sent)
- * 2. terminated -- the vm is terminated (guaranteed to be the last event sent)
- * 3. suspended client|step|breakpoint N
- * -- the vm is suspended by client, due to a stepping request or
- * the breakpoint at line N is hit
- * 4. resumed client|step
- * -- the vm resumes execution by client or step
- *
- * @param event
- */
- protected void sendEvent(DebugEvent event) {
- DebugUtils.println("SERVER sending event: " + event.toString());
- synchronized (eventSocket) {
- try {
- byte[] data = SerializationHelper.serialize(event);
- eventWriter.writeInt(data.length);
- eventWriter.write(data);
- eventWriter.flush();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- /* (non-Javadoc)
- * @see lua.debug.DebugEventListener#notifyDebugEvent(lua.debug.DebugEvent)
- */
- public void notifyDebugEvent(DebugEvent event) {
- sendEvent(event);
- }
-
- /* (non-Javadoc)
- * @see lua.debug.DebugRequestListener#handleRequest(java.lang.String)
- */
- public DebugResponse handleRequest(DebugRequest request) {
- if (DebugUtils.IS_DEBUG) {
- DebugUtils.println("handling request: " + request.toString());
- }
-
- DebugResponse response = vm.handleRequest(request);
- return response;
- }
-}
diff --git a/src/main/java/lua/debug/j2se/DebugSupportImpl.java b/src/main/java/lua/debug/j2se/DebugSupportImpl.java
new file mode 100644
index 00000000..283c2a84
--- /dev/null
+++ b/src/main/java/lua/debug/j2se/DebugSupportImpl.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+* Copyright (c) 2007 LuaJ. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+******************************************************************************/
+package lua.debug.j2se;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import lua.debug.DebugSupport;
+import lua.debug.DebugUtils;
+import lua.debug.event.DebugEvent;
+
+public class DebugSupportImpl extends DebugSupport {
+ protected ServerSocket requestSocket;
+ protected Socket clientRequestSocket;
+
+ protected ServerSocket eventSocket;
+ protected Socket clientEventSocket;
+
+ public DebugSupportImpl(int requestPort, int eventPort) {
+ super(requestPort, eventPort);
+ }
+
+ /* (non-Javadoc)
+ * @see lua.debug.j2se.DebugSupport#start()
+ */
+ public synchronized void start() throws IOException {
+ this.requestSocket = new ServerSocket(requestPort);
+ this.clientRequestSocket = requestSocket.accept();
+ this.requestReader
+ = new DataInputStream(clientRequestSocket.getInputStream());
+ this.requestWriter
+ = new DataOutputStream(clientRequestSocket.getOutputStream());
+
+ this.eventSocket = new ServerSocket(eventPort);
+ this.clientEventSocket = eventSocket.accept();
+ this.eventWriter
+ = new DataOutputStream(clientEventSocket.getOutputStream());
+
+ super.start();
+ }
+
+ protected void releaseServer() {
+ super.releaseServer();
+
+ if (clientRequestSocket != null) {
+ try {
+ clientRequestSocket.close();
+ } catch (IOException e) {}
+ }
+
+ if (requestSocket != null) {
+ try {
+ requestSocket.close();
+ } catch (IOException e) {}
+ }
+
+ if (clientEventSocket != null) {
+ try {
+ clientEventSocket.close();
+ } catch (IOException e) {}
+ }
+
+ if (eventSocket != null){
+ try {
+ eventSocket.close();
+ } catch (IOException e) {}
+ }
+ }
+
+ protected void handleRequest() {
+ synchronized (clientRequestSocket) {
+ super.handleRequest();
+ }
+ }
+
+ /**
+ * This method provides the second communication channel with the debugging
+ * client. The server can send events via this channel to notify the client
+ * about debug events (see below) asynchronously.
+ *
+ * The following events can be fired:
+ * 1. started -- the vm is started and ready to receive debugging requests
+ * (guaranteed to be the first event sent)
+ * 2. terminated -- the vm is terminated (guaranteed to be the last event sent)
+ * 3. suspended client|step|breakpoint N
+ * -- the vm is suspended by client, due to a stepping request or
+ * the breakpoint at line N is hit
+ * 4. resumed client|step
+ * -- the vm resumes execution by client or step
+ *
+ * @param event
+ */
+ protected void sendEvent(DebugEvent event) {
+ synchronized (eventSocket) {
+ super.sendEvent(event);
+ }
+ }
+}
diff --git a/src/main/java/lua/debug/j2se/StandardLuaJVM.java b/src/main/java/lua/debug/j2se/StandardLuaJVM.java
index cfc0904c..9e5cea61 100644
--- a/src/main/java/lua/debug/j2se/StandardLuaJVM.java
+++ b/src/main/java/lua/debug/j2se/StandardLuaJVM.java
@@ -25,24 +25,14 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.Timer;
-import java.util.TimerTask;
import lua.GlobalState;
import lua.StackState;
import lua.addon.luacompat.LuaCompat;
import lua.addon.luajava.LuaJava;
import lua.debug.DebugStackState;
+import lua.debug.DebugSupport;
import lua.debug.DebugUtils;
-import lua.debug.event.DebugEvent;
-import lua.debug.event.DebugEventType;
-import lua.debug.request.DebugRequest;
-import lua.debug.request.DebugRequestListener;
-import lua.debug.request.DebugRequestType;
-import lua.debug.response.DebugResponse;
-import lua.debug.response.DebugResponseSimple;
import lua.io.Closure;
import lua.io.LoadState;
import lua.io.Proto;
@@ -55,9 +45,8 @@ import lua.value.LValue;
* @author: Shu Lei
* @version: 1.0
*/
-public class StandardLuaJVM implements DebugRequestListener {
+public class StandardLuaJVM {
protected boolean isDebugMode = false;
- protected DebugSupport debugSupport;
protected int requestPort;
protected int eventPort;
protected String script;
@@ -125,19 +114,15 @@ public class StandardLuaJVM implements DebugRequestListener {
throw new ParseException("script is missing.");
}
- try {
- this.script = URLDecoder.decode(args[0], "UTF-8");
- DebugUtils.println("Lua script to run: " + this.script);
- int scriptArgsLength = args.length - 1;
- if (scriptArgsLength > 0) {
- this.scriptArgs = new String[scriptArgsLength];
- for (int i = 1; i < args.length; i++) {
- this.scriptArgs[i - 1] = URLDecoder.decode(args[i], "UTF-8");
- }
- }
- } catch (UnsupportedEncodingException e) {
- throw new ParseException("Malformed program argument strings: " + e.getMessage());
- }
+ this.script = args[0];
+ DebugUtils.println("Lua script to run: " + this.script);
+ int scriptArgsLength = args.length - 1;
+ if (scriptArgsLength > 0) {
+ this.scriptArgs = new String[scriptArgsLength];
+ for (int i = 1; i < args.length; i++) {
+ this.scriptArgs[i - 1] = args[i];
+ }
+ }
}
// end of command line parsing utilities
@@ -184,7 +169,7 @@ public class StandardLuaJVM implements DebugRequestListener {
LuaCompat.install();
}
- public void doRun() throws IOException {
+ protected void doRun() throws IOException {
init();
// new lua state
@@ -208,10 +193,13 @@ public class StandardLuaJVM implements DebugRequestListener {
state.doCall(c, vargs);
}
- private void doDebug() throws IOException {
+ protected void doDebug() throws IOException {
DebugUtils.println("setting up LuaJava and debug stack state...");
init();
+ // new lua debug state
+ state = new DebugStackState();
+
// load the Lua file
DebugUtils.println("loading Lua script '" + getScript() + "'");
InputStream is = new FileInputStream(new File(getScript()));
@@ -219,80 +207,26 @@ public class StandardLuaJVM implements DebugRequestListener {
// set up debug support if the file is successfully loaded
DebugUtils.println("start debugging...");
- this.debugSupport = new DebugSupport(this, getRequestPort(), getEventPort());
- DebugUtils.println("created client request socket connection...");
- debugSupport.start();
-
- // new lua debug state
- state = new DebugStackState();
- getDebugState().addDebugEventListener(debugSupport);
+ DebugSupport debugSupport
+ = new DebugSupportImpl(getRequestPort(), getEventPort());
+ getDebugState().setDebugSupport(debugSupport);
getDebugState().suspend();
// create closure and execute
final Closure c = new Closure(state, p);
-
- new Thread(new Runnable() {
- public void run() {
- 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]);
- }
-
- getDebugState().doCall(c, vargs);
- stop();
- }
- }).start();
-
- debugSupport.notifyDebugEvent(new DebugEvent(DebugEventType.started));
+ 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]);
+ }
+ getDebugState().doCall(c, vargs);
+ getDebugState().stop();
}
private DebugStackState getDebugState() {
return (DebugStackState)state;
}
-
- /* (non-Javadoc)
- * @see lua.debug.DebugRequestListener#handleRequest(java.lang.String)
- */
- public DebugResponse handleRequest(DebugRequest request) {
- if (!isDebug()) {
- throw new UnsupportedOperationException("Must be in debug mode to handle the debug requests");
- }
-
- DebugRequestType requestType = request.getType();
- if (DebugRequestType.suspend == requestType) {
- DebugResponse status = getDebugState().handleRequest(request);
- DebugEvent event = new DebugEvent(DebugEventType.suspendedByClient);
- debugSupport.notifyDebugEvent(event);
- return status;
- } else if (DebugRequestType.resume == requestType) {
- DebugResponse status = getDebugState().handleRequest(request);
- DebugEvent event = new DebugEvent(DebugEventType.resumedByClient);
- debugSupport.notifyDebugEvent(event);
- return status;
- } else if (DebugRequestType.exit == requestType) {
- stop();
- return DebugResponseSimple.SUCCESS;
- } else {
- return getDebugState().handleRequest(request);
- }
- }
-
- protected void stop() {
- if (this.debugSupport != null) {
- DebugEvent event = new DebugEvent(DebugEventType.terminated);
- debugSupport.notifyDebugEvent(event);
- Timer timer = new Timer("DebugServerDeathThread");
- timer.schedule(new TimerTask() {
- public void run() {
- debugSupport.stop();
- debugSupport = null;
- }
- }, 300);
- }
- getDebugState().exit();
- }
/**
* Parses the command line arguments and executes/debugs the lua program.
diff --git a/src/main/java/lua/debug/request/DebugRequestType.java b/src/main/java/lua/debug/request/DebugRequestType.java
index f6ad5e62..49980ee1 100644
--- a/src/main/java/lua/debug/request/DebugRequestType.java
+++ b/src/main/java/lua/debug/request/DebugRequestType.java
@@ -38,7 +38,8 @@ public class DebugRequestType extends EnumType {
public static final DebugRequestType callgraph = new DebugRequestType("callgraph", 7);
public static final DebugRequestType stack = new DebugRequestType("stack", 8);
public static final DebugRequestType step = new DebugRequestType("step", 9);
-
+ public static final DebugRequestType start = new DebugRequestType("start", 10);
+
protected static final DebugRequestType[] ENUMS = new DebugRequestType[] {
suspend,
resume,
@@ -49,7 +50,8 @@ public class DebugRequestType extends EnumType {
watchpointClear,
callgraph,
stack,
- step
+ step,
+ start
};
public DebugRequestType(String name, int ordinal) {