All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scaladebugger.api.lowlevel.breakpoints.StandardBreakpointManager.scala Maven / Gradle / Ivy

The newest version!
package org.scaladebugger.api.lowlevel.breakpoints

import com.sun.jdi.request.{EventRequestManager, BreakpointRequest}
import org.scaladebugger.api.lowlevel.classes.ClassManager
import org.scaladebugger.api.lowlevel.requests.JDIRequestArgument
import org.scaladebugger.api.lowlevel.requests.properties.{EnabledProperty, SuspendPolicyProperty}
import org.scaladebugger.api.utils.{MultiMap, Logging}
import com.sun.jdi.Location

import scala.collection.JavaConverters._
import scala.util.{Try, Failure}

/**
 * Represents the manager for breakpoint requests.
 *
 * @param eventRequestManager The manager used to create breakpoint requests
 * @param classManager The class manager associated with the virtual machine,
 *                      used to retrieve location information
 */
class StandardBreakpointManager(
  private val eventRequestManager: EventRequestManager,
  private val classManager: ClassManager
) extends BreakpointManager with Logging {
  import org.scaladebugger.api.lowlevel.requests.Implicits._

  private val breakpointRequests =
    new MultiMap[BreakpointRequestInfo, Seq[BreakpointRequest]]

  /**
   * Retrieves the list of breakpoints contained by this manager.
   *
   * @return The collection of breakpoints in the form of information
   */
  override def breakpointRequestList: Seq[BreakpointRequestInfo] =
    breakpointRequests.keys

  /**
   * Retrieves the list of breakpoints contained by this manager.
   *
   * @return The collection of breakpoints by id
   */
  override def breakpointRequestListById: Seq[String] = breakpointRequests.ids

  /**
   * Creates and enables a breakpoint on the specified line of the class.
   *
   * @param requestId The id of the request used for lookup and removal
   * @param fileName The name of the file to set a breakpoint
   * @param lineNumber The number of the line to break
   * @param extraArguments Any additional arguments to provide to the request
   *
   * @return Success(id) if successful, otherwise Failure
   */
  override def createBreakpointRequestWithId(
    requestId: String,
    fileName: String,
    lineNumber: Int,
    extraArguments: JDIRequestArgument*
  ): Try[String] = {
    // Retrieve the available locations for the specified line
    val locations = classManager
      .linesAndLocationsForFile(fileName)
      .flatMap(_.get(lineNumber))
      .getOrElse(Nil)

    // Exit early if no locations are available
    if (locations.isEmpty)
      return Failure(NoBreakpointLocationFound(fileName, lineNumber))

    val arguments = Seq(
      SuspendPolicyProperty.EventThread,
      EnabledProperty(value = true)
    ) ++ extraArguments

    // TODO: Back out breakpoint creation if a failure occurs
    val requests = Try(locations.map(
      eventRequestManager.createBreakpointRequest(_: Location, arguments: _*)
    ))

    val isPending = false
    if (requests.isSuccess) {
      val l = s"$fileName:$lineNumber"
      logger.trace(s"Created breakpoint request with id '$requestId' at $l")
      breakpointRequests.putWithId(
        requestId,
        BreakpointRequestInfo(
          requestId,
          isPending,
          fileName,
          lineNumber,
          extraArguments
        ),
        requests.get
      )
    }

    // If no exception was thrown, assume that we succeeded
    requests.map(_ => requestId)
  }

  /**
   * Determines whether or not the breakpoint for the specific file's line.
   *
   * @param fileName The name of the file whose line to reference
   * @param lineNumber The number of the line to check for a breakpoint
   *
   * @return True if a breakpoint exists, otherwise false
   */
  override def hasBreakpointRequest(
    fileName: String,
    lineNumber: Int
  ): Boolean = {
    breakpointRequests.hasWithKeyPredicate(b =>
      b.fileName == fileName && b.lineNumber == lineNumber
    )
  }

  /**
   * Determines whether or not the breakpoint with the specified id exists.
   *
   * @param requestId The id of the request
   *
   * @return True if a breakpoint exists, otherwise false
   */
  override def hasBreakpointRequestWithId(requestId: String): Boolean = {
    breakpointRequests.hasWithId(requestId)
  }

  /**
   * Returns the collection of breakpoints representing the breakpoint for the
   * specified line.
   *
   * @param fileName The name of the file whose line to reference
   * @param lineNumber The number of the line to check for breakpoints
   *
   * @return Some collection of breakpoints for the specified line, or None if
   *         the specified line has no breakpoints
   */
  override def getBreakpointRequest(
    fileName: String,
    lineNumber: Int
  ): Option[Seq[BreakpointRequest]] = {
    val requests = breakpointRequests.getWithKeyPredicate(b =>
      b.fileName == fileName && b.lineNumber == lineNumber
    ).flatten

    if (requests.nonEmpty) Some(requests) else None
  }

  /**
   * Returns the collection of breakpoints with the specified id.
   *
   * @param requestId The id of the request
   *
   * @return Some collection of breakpoints for the specified line, or None if
   *         the specified line has no breakpoints
   */
  override def getBreakpointRequestWithId(
    requestId: String
  ): Option[Seq[BreakpointRequest]] = {
    breakpointRequests.getWithId(requestId)
  }

  /**
   * Returns the arguments for a breakpoint request with the specified id.
   *
   * @param requestId The id of the request
   *
   * @return Some breakpoint arguments if found, otherwise None
   */
  override def getBreakpointRequestInfoWithId(
    requestId: String
  ): Option[BreakpointRequestInfo] = {
    breakpointRequests.getKeyWithId(requestId)
  }

  /**
   * Removes the breakpoint on the specified line of the file.
   *
   * @param fileName The name of the file to remove the breakpoint
   * @param lineNumber The number of the line to break
   *
   * @return True if successfully removed breakpoint, otherwise false
   */
  override def removeBreakpointRequest(
    fileName: String,
    lineNumber: Int
  ): Boolean = {
    val ids = breakpointRequests.getIdsWithKeyPredicate(b =>
      b.fileName == fileName && b.lineNumber == lineNumber
    )

    ids.nonEmpty && ids.forall(removeBreakpointRequestWithId)
  }

  /**
   * Removes the breakpoint with the specified id.
   *
   * @param requestId The id of the request
   *
   * @return True if successfully removed breakpoint, otherwise false
   */
  override def removeBreakpointRequestWithId(
    requestId: String
  ): Boolean = {
    val requests = breakpointRequests.removeWithId(requestId)

    requests.map(_.asJava).foreach(eventRequestManager.deleteEventRequests)

    requests.nonEmpty
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy