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

scalut.daemon.Bootstrap.scala Maven / Gradle / Ivy

The newest version!
package scalut.daemon


import java.util.Scanner

import org.apache.commons.daemon.{Daemon, DaemonContext}
import scalut.util.StringHelper
import scalut.logging.LoggingProvider

import scala.concurrent.Await
import scala.concurrent.duration.Duration
import scala.util.Try


abstract class Bootstrap extends Daemon with LoggingProvider {

  protected lazy val server: Server = newServer()

  protected def newServer(): Server

  /**
    * Java Service Wrapper for Linux.
    */
  def jswApplyCmd(args: Array[String]): Unit = {
    val cmd =
      if (args.length > 0)
        args.last
      else
        "start"

    cmd match {
      case "start" => start()
      case "stop" => stop()
      case _ => println(s"Unknown command '$cmd'.")
    }
  }

  /**
    * Run `cmd` and wait for next command from keyboard.
    */
  protected def waitKeyboardCommand(cmd: String = StringHelper.EMPTY): Unit = {
    Console.in.mark(0)
    val scanner = new Scanner(Console.in)

    def welcome(): Unit = {
      println("Type command...")
    }

    lazy val listener: Server.EventListener = (source: Server, event: Server.State.Type) =>
      event match {
        case Server.State.STARTED =>
          println("Type 'stop' to stop server.")
        case Server.State.STOPPED =>
          server.unsubscribe(listener)
          scanner.close()
        case _ => // ignore
      }

    server.subscribe(listener)

    // Уже подписаны на изменения сервера,
    // запускаем первую команду и ждем...
    if (StringHelper.nonEmpty(cmd))
      jswApplyCmd(Array(cmd))

    // Wait until receive command from keyboard
    // Throw IllegalStateException when scanner closed, so surround in Try.
    while (Try(scanner.hasNextLine).getOrElse(false)) {
      scanner.nextLine() match {
        // При destroy или stop выполнится обработчик события
        // и если нужно закроет сканер.

        case StringHelper.EMPTY => // ничего не делаем
        case line => jswApplyCmd(Array(line))
      }
      if (!server.isStopped)
        welcome()
    }
  }

  /**
    * For Windows.
    */
  def windowsService(args: Array[String]): Unit = {
    var cmd = "start"
    if (args.length > 0)
      cmd = args(0)

    cmd match {
      case "start" =>
        windowsStart()
      // Например, если в терминале или в IDE сделали прерывание выполнения.
      //sys.addShutdownHook {windowsStop()}
      case "stop" => windowsStop()
      case _ =>
    }
  }

  protected def block(): Unit = {
    while (!server.isStopped) {
      // don't return until stopped
      this.synchronized {
        try {
          this.wait(30000) // wait 30 sec and check if stopped
        }
        catch {
          case ex: InterruptedException =>
            log.debug("windowsStart: Thread interrupted, probably means we're shutting down now.", ex)
        }
      }
    }
  }

  protected def unblock(): Unit = {
    /*while (!server.isStopped) {
      this.synchronized {
        try {
          this.wait(1000) // wait 1 sec and check if stopped
        }
        catch {
          case ex: InterruptedException =>
            logger.debug("windowsStop: Thread interrupted, probably means we're shutting down now.", ex)
        }
      }
    }*/
    this.synchronized {
      // stop the start loop
      this.notify()
    }
  }

  def windowsStart(): Unit = {
    log.debug("windowsStart called")
    start()
    block()
  }

  def windowsStop(): Unit = {
    log.debug("windowsStop called")
    stop()
    unblock()
  }

  // Implementing the Daemon interface is not required for Windows but is for Linux.
  def init(context: DaemonContext): Unit = {
    log.debug(s"Daemon initialized with arguments: ${context.getArguments}.")
  }

  def start(): Unit = {
    log.debug("Daemon start")
    if (server.isStopped) {
      log.debug("Starting the Engine")
      Await.result(server.start(), Duration.Inf)
      log.debug("Engine started")
    }
  }

  def stop(): Unit = {
    log.debug("Daemon stop")
    if (!server.isStopped) {
      log.debug("Stopping the Engine")
      Await.result(server.stop(), Duration.Inf)
      log.debug("Engine stopped")
    }
  }

  def destroy(): Unit = {
    log.debug("Daemon destroy")
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy