package com.aptana.ruby.internal.debug.core.commands; import java.io.IOException; import java.io.PrintWriter; import java.net.Socket; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import com.aptana.ruby.debug.core.RubyDebugCorePlugin; import com.aptana.ruby.debug.core.launching.IRubyLaunchConfigurationConstants; import com.aptana.ruby.internal.debug.core.DebuggerNotFoundException; import com.aptana.ruby.internal.debug.core.parsing.AbstractReadStrategy; import com.aptana.ruby.internal.debug.core.parsing.MultiReaderStrategy; import com.aptana.ruby.internal.debug.core.parsing.SuspensionReader; public abstract class AbstractDebuggerConnection { private static final String PARSER_CLASSNAMES = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer"; //$NON-NLS-1$ private static final String ENCODING = "UTF-8"; //$NON-NLS-1$ private int commandPort; private Socket commandSocket; private PrintWriter writer; private AbstractReadStrategy commandReadStrategy; private String host; public AbstractDebuggerConnection(int port) { this(IRubyLaunchConfigurationConstants.DEFAULT_REMOTE_HOST, port); } public AbstractDebuggerConnection(String host, int port) { super(); this.host = host; this.commandPort = port; } /* * connect to the debugger. After the connection is established the debugger listens for control commands */ public abstract void connect() throws DebuggerNotFoundException, IOException; /* * start the debugger. Must be connected to start. */ public abstract SuspensionReader start() throws DebuggerNotFoundException, IOException; public abstract boolean isStarted(); /* * always call via Command.execute */ protected AbstractReadStrategy sendCommand(AbstractCommand command) throws DebuggerNotFoundException, IOException { if (!isCommandPortConnected()) { throw new IllegalStateException(command + " could not be sent since command socket is not open"); //$NON-NLS-1$ } RubyDebugCorePlugin.debug("Sending command: " + command.getCommand()); //$NON-NLS-1$ getWriter().println(command.getCommand()); return getCommandReadStrategy(); } public AbstractReadStrategy getCommandReadStrategy() { return commandReadStrategy; } protected void createCommandConnection() throws DebuggerNotFoundException, IOException { getSocket(); XmlPullParser xpp = createXpp(commandSocket); commandReadStrategy = new MultiReaderStrategy(xpp); } public boolean isCommandPortConnected() { return commandSocket != null; } protected Socket getSocket() throws IOException, DebuggerNotFoundException { if (commandSocket == null) { commandSocket = acquireSocket(host, commandPort); if (commandSocket == null) { throw new DebuggerNotFoundException("Could not connect to debugger on port " + commandPort); //$NON-NLS-1$ } } return commandSocket; } protected static Socket acquireSocket(String host, int port) throws IOException { Socket socket = null; int tryCount = 50; for (int i = 0; i < tryCount; i++) { try { socket = new Socket(host, port); break; } catch (IOException e) { try { Thread.sleep(500); } catch (InterruptedException e1) { } } } return socket; } private PrintWriter getWriter() throws IOException, DebuggerNotFoundException { if (writer == null) { writer = new PrintWriter(commandSocket.getOutputStream(), true); } return writer; } protected static XmlPullParser createXpp(Socket socket) { XmlPullParser xpp = null; try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(PARSER_CLASSNAMES, null); xpp = factory.newPullParser(); xpp.setInput(socket.getInputStream(), ENCODING); } catch (XmlPullParserException e) { // TODO: log e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return xpp; } public int getCommandPort() { return commandPort; } public void exit() throws IOException { if (commandSocket != null) { commandSocket.close(); } } }