<NME> SocketListenConnectorScala.scala
<BEF> ADDFILE
<MSG> Merge pull request #220 from skyluc/issue/remote-scala-debugger-1001129

Added attach and listen Scala remote connectors
<DFF> @@ -0,0 +1,213 @@
+package scala.tools.eclipse.launching
+
+import java.io.IOException
+import java.util.{ List => JList, Map => JMap }
+
+import scala.tools.eclipse.debug.ScalaDebugPlugin
+import scala.tools.eclipse.debug.model.ScalaDebugTarget
+
+import org.eclipse.core.runtime.IProgressMonitor
+import org.eclipse.core.runtime.IStatus
+import org.eclipse.core.runtime.Status
+import org.eclipse.core.runtime.jobs.Job
+import org.eclipse.debug.core.DebugEvent
+import org.eclipse.debug.core.DebugPlugin
+import org.eclipse.debug.core.ILaunch
+import org.eclipse.debug.core.model.IProcess
+import org.eclipse.debug.core.model.IStreamsProxy
+import org.eclipse.jdi.Bootstrap
+
+import com.sun.jdi.connect.Connector
+import com.sun.jdi.connect.ListeningConnector
+import com.sun.jdi.connect.TransportTimeoutException
+
+/**
+ * Listen connector creating a Scala debug session.
+ * Added to the platform through extension point.
+ */
+class SocketListenConnectorScala extends SocketConnectorScala {
+  import SocketConnectorScala._
+
+  // from scala.tools.eclipse.launching.SocketConnectorScala
+
+  override def connector(): ListeningConnector = {
+    import scala.collection.JavaConverters._
+    Bootstrap.virtualMachineManager().listeningConnectors().asScala.find(_.name() == SocketListenName).getOrElse(
+        throw ScalaDebugPlugin.wrapInCoreException("Unable to find JDI ListeningConnector", null))
+  }
+
+  // from org.eclipse.jdt.launching.IVMConnector
+
+  override val getArgumentOrder: JList[String] = {
+    import scala.collection.JavaConverters._
+    List(PortKey).asJava
+  }
+
+  override val getIdentifier: String = ScalaDebugPlugin.id + ".socketListenConnector"
+
+  override def getName(): String = "Scala debugger (Socket Listen)"
+
+  override def connect(params: JMap[_, _], monitor: IProgressMonitor, launch: ILaunch) {
+    val arguments = generateArguments(params)
+
+    // the port number is needed for the process label. It should be available if we got that far
+    import scala.collection.JavaConverters._
+    val port = arguments.asScala.get("port") match {
+      case Some(e: Connector.IntegerArgument) =>
+        e.intValue()
+      case _ =>
+        0
+    }
+
+    // a fake process to display information
+    val process = ListenForConnectionProcess(launch, port)
+
+    // Start a job to wait for VM connections
+    val job = new ListenForConnectionJob(launch, process, connector(), arguments);
+    job.setPriority(Job.SHORT)
+
+    job.schedule()
+
+  }
+
+  // ------------
+
+}
+
+object ListenForConnectionProcess {
+  /**
+   * Create a process instance.
+   */
+  def apply(launch: ILaunch, port: Int): ListenForConnectionProcess = {
+    val process = new ListenForConnectionProcess(launch, port)
+    launch.addProcess(process)
+    process.fireEvent(DebugEvent.CREATE)
+    process
+  }
+}
+
+/**
+ * A fake process which is displayed while waiting for a VM to connect
+ */
+class ListenForConnectionProcess private (launch: ILaunch, port: Int) extends IProcess {
+
+  // -- from org.eclipse.debug.core.model.IProcess
+
+  def getExitValue(): Int = {
+    // should only be used when connection failed
+    -1
+  }
+
+  def getAttribute(id: String): String = {
+    // not supported
+    null
+  }
+
+  def setAttribute(id: String, value: String) {
+    // nothing to do
+  }
+
+  def getStreamsProxy(): IStreamsProxy = {
+    // not supported
+    null
+  }
+
+  def getLaunch(): ILaunch = launch
+
+  def getLabel(): String = label
+
+  // -- from org.eclipse.debug.core.model.ITerminate
+
+  def terminate() {
+    // not supported
+  }
+
+  override def isTerminated(): Boolean = isTerminatedFlag
+
+  def canTerminate(): Boolean = false
+
+  // -- from org.eclipse.core.runtime.IAdaptable
+
+  def getAdapter(adapter: Class[_]): Object = null
+
+  // ----------
+
+  /**
+   * Called when no VM connected before the timeout.
+   * Set the flag and the label accordingly.
+   */
+  def failed(message: String) {
+    label = message
+    isTerminatedFlag = true
+    fireEvent(DebugEvent.TERMINATE)
+  }
+
+  /**
+   * Called when a VM has connected. The fake process is destroyed
+   */
+  def done() {
+    launch.removeProcess(this)
+  }
+
+  /**
+   * Flag holding the terminated state
+   */
+  @volatile
+  private var isTerminatedFlag = false
+
+  /**
+   * Label displayed. Initial value to 'waiting...'. Switched to error message after faiture.
+   */
+  @volatile
+  private var label = "Waiting for connection on port %d...".format(port)
+
+  /**
+   * Utility method to fire debug events.
+   */
+  private def fireEvent(kind: Int) {
+    DebugPlugin.getDefault().fireDebugEventSet(Array(new DebugEvent(this, kind)))
+  }
+}
+
+/**
+ * Job waiting for a VM to connect.
+ * If it is successful, it creates a debug target, otherwise an error message is displayed in the debug view.
+ */
+class ListenForConnectionJob(launch: ILaunch, process: ListenForConnectionProcess, connector: ListeningConnector, arguments: JMap[String, Connector.Argument]) extends Job("Scala debugger remote connection listener") {
+  import SocketConnectorScala._
+
+  // -- from org.eclipse.core.runtime.jobs.Job
+
+  override def run(monitor: IProgressMonitor): IStatus = {
+    try {
+      connector.startListening(arguments)
+      val virtualMachine = connector.accept(arguments)
+      connector.stopListening(arguments)
+
+      ScalaDebugTarget(virtualMachine, launch, null, true, allowTerminate(launch))
+
+      Status.OK_STATUS
+    } catch {
+      case e: TransportTimeoutException =>
+        connectionFailed("No connection received before timeout expired")
+        Status.OK_STATUS
+      case e: IOException =>
+        connectionFailed("Problem while waiting to receive connection. See log for more details")
+        ScalaDebugPlugin.wrapInErrorStatus("Problem while waiting to receive connection", e)
+      case e: Exception =>
+        connectionFailed("Unexpected problem while waiting to receive connection. See log for more details")
+        ScalaDebugPlugin.wrapInErrorStatus("Unexpected problem while waiting to receive connection", e)
+    }
+  }
+
+  // ------------
+
+  def connectionSuccesful() {
+    process.done()
+  }
+
+  def connectionFailed(message: String) {
+    process.failed(message)
+  }
+
+}
\ No newline at end of file

{'addition_count': 213, 'commit_subject': 'Merge pull request #220 from skyluc/issue/remote-scala-debugger-1001129', 'deletion_count': 0, 'file_extension': '.scala', 'lang': 'scala-ide', 'license': 'bsd-3-clause', 'repo_name': 'scala-ide/scala-ide'}