как отменить ConsoleReader.readLine () - PullRequest
10 голосов
/ 17 июля 2011

Прежде всего, я изучаю скала и новичок в мире Java.Я хочу создать консоль и запустить эту консоль как службу, которую вы могли бы запускать и останавливать.Мне удалось запустить ConsoleReader в Actor, но я не знаю, как правильно остановить ConsoleReader.Вот код:

import eu.badmood.util.trace
import scala.actors.Actor._

import tools.jline.console.ConsoleReader

object Main {

  def main(args:Array[String]){
    //start the console
    Console.start(message => {
      //handle console inputs
      message match {
        case "exit" => Console.stop()
        case _ => trace(message)
      }
    })

    //try to stop the console after a time delay
    Thread.sleep(2000)
    Console.stop()

  }

}

object Console {

  private val consoleReader = new ConsoleReader()

  private var running = false

  def start(handler:(String)=>Unit){
    running = true
    actor{
      while (running){
        handler(consoleReader.readLine("\33[32m> \33[0m"))
      }
    }
  }

  def stop(){
    //how to cancel an active call to ConsoleReader.readLine ?
    running = false
  }

}

Я также ищу любой совет относительно этого кода!

Ответы [ 3 ]

3 голосов
/ 17 июля 2011

Основной вызов для чтения символов из ввода блокируется.На платформе, отличной от Windows, он будет использовать System.in.read(), а в Windows - org.fusesource.jansi.internal.WindowsSupport.readByte.

Таким образом, ваша задача состоит в том, чтобы вернуть этот блокирующий вызов, когда вы хотите остановить консольную службу.См. http://www.javaspecialists.eu/archive/Issue153.html и Возможно ли чтение из InputStream с таймаутом? для некоторых идей ... Как только вы поймете это, получите read return -1, когда ваш консольный сервисостанавливается, так что ConsoleReader думает, что это сделано.Вам понадобится ConsoleReader, чтобы использовать вашу версию этого вызова:

  • Если вы работаете в Windows, вам, вероятно, придется переопределить tools.jline.AnsiWindowsTerminal и использовать конструктор ConsoleReader, который принимаетTerminal (в противном случае AnsiWindowsTerminal будет просто использовать WindowsSupport.readByte` напрямую)
  • В Unix существует один ConsoleReader конструктор, который принимает InputStream, вы можете предоставить свою собственную оболочку для System.in

Еще несколько мыслей:

  • Уже существует scala.Console объект, поэтому для меньшей путаницы назовите ваш по-другому.
  • System.in isуникальный ресурс, поэтому вам, вероятно, нужно убедиться, что только один вызывающий абонент использует Console.readLine одновременно.Прямо сейчас start будет напрямую звонить на readLine, и несколько абонентов смогут позвонить на start.Вероятно, консольная служба может readLine и поддерживать список обработчиков.
1 голос
/ 18 июля 2011

Предполагая, что ConsoleReader.readLine реагирует на прерывание потока, вы можете переписать Консоль, чтобы использовать Поток, который затем можете прервать, чтобы остановить его.

object Console {

  private val consoleReader = new ConsoleReader()
  private var thread : Thread = _

  def start(handler:(String)=>Unit) : Thread = {
    thread = new Thread(new Runnable {
      override def run() {
        try {
          while (true) {
            handler(consoleReader.readLine("\33[32m> \33[0m"))
          }
        } catch {
          case ie: InterruptedException =>
        }
      }
    })
    thread.start()
    thread
  }

  def stop() {
    thread.interrupt()
  }

}
0 голосов
/ 23 ноября 2012

Вы можете перезаписать ваш ConsoleReader InputStream.ИМХО, это разумно, потому что STDIN - это «медленный» поток.Пожалуйста, улучшите пример для ваших нужд.Это только набросок, но он работает:

def createReader() =
terminal.synchronized {
  val reader = new ConsoleReader
  terminal.enableEcho()
  reader.setBellEnabled(false)
  reader.setInput(new InputStreamWrapper(reader.getInput())) // turn on InterruptedException for InputStream.read
  reader
}

с упаковкой InputStream:

class InputStreamWrapper(is: InputStream, val timeout: Long = 50) extends FilterInputStream(is) {
@tailrec
final override def read(): Int = {
  if (is.available() != 0)
    is.read()
  else {
    Thread.sleep(timeout)
    read()
  }
}

}

PS Я пытался использовать NIO - много проблем сSystem.in (особенно кроссплатформенный).Я вернулся к этому варианту.Загрузка процессора составляет около 0%.Это подходит для такого интерактивного приложения.

...