Scala chat application, blocking issue
<p>I'm writing a chat application in Scala, the problem is with the clients, the client reads from StdIn (which blocks) before sending the data to the echo server, so if multiple clients are connected then they don't receive data from the server until reading from StdIn has completed. I'm thinking that local IO, i.e reading from StdIn and reading/writing to the socket should be on separate threads but I can't think of a way to do this, below is the Client singleton code:</p>

<pre><code>import java.net._
import scala.io._
import java.io._
import java.security._

object Client {

  var msgAcc = ""

  def main(args: Array[String]): Unit = {
    val conn = new ClientConnection(InetAddress.getByName(args(0)), args(1).toInt)
    val server = conn.connect()
    println("Enter a username")
    val user = new User(StdIn.readLine())
    println("Welcome to the chat " + user.username)
    sys.addShutdownHook(this.shutdown(conn, server))
    while (true) {
    val txMsg = StdIn.readLine()//should handle with another thread?
    if (txMsg != null) {
      conn.sendMsg(server, user, txMsg)
      val rxMsg = conn.getMsg(server)
      val parser = new JsonParser(rxMsg)
      val formattedMsg = parser.formatMsg(parser.toJson()) 
      println(formattedMsg)
      msgAcc = msgAcc + formattedMsg + "\n"
      }
    }
  }

  def shutdown(conn: ClientConnection, server: Socket): Unit = {
    conn.close(server)
    val fileWriter = new BufferedWriter(new FileWriter(new File("history.txt"), true))
    fileWriter.write(msgAcc) 
    fileWriter.close()
    println("Leaving chat, thanks for using")
  }

}
</code></pre>

<p>below is the ClientConnection class:</p>

<pre><code>import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.SocketFactory
import java.net.Socket
import java.net.InetAddress
import java.net.InetSocketAddress
import java.security._
import java.io._
import scala.io._
import java.util.GregorianCalendar
import java.util.Calendar
import java.util.Date
import com.sun.net.ssl.internal.ssl.Provider
import scala.util.parsing.json._

class ClientConnection(host: InetAddress, port: Int) {

  def connect(): Socket = {
    Security.addProvider(new Provider())
    val sslFactory = SSLSocketFactory.getDefault()
    val sslSocket = sslFactory.createSocket(host, port).asInstanceOf[SSLSocket]
    sslSocket
   }

  def getMsg(server: Socket): String = new BufferedSource(server.getInputStream()).getLines().next()

  def sendMsg(server: Socket, user: User, msg: String): Unit = {
    val out = new PrintStream(server.getOutputStream())
    out.println(this.toMinifiedJson(user.username, msg))
    out.flush()
  }  

  private def toMinifiedJson(user: String, msg: String): String = {
    s"""{"time":"${this.getTime()}","username":"$user","msg":"$msg"}"""
  }

  private def getTime(): String = {
    val cal = Calendar.getInstance()
    cal.setTime(new Date())
    "(" + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND) + ")"
  }

  def close(server: Socket): Unit = server.close()
}
</code></pre>

<p>This is the Client singleton using a Thread to read from standard input: </p>

<pre><code>import java.net._
import scala.io._
import java.io._
import java.security._
import java.util.NoSuchElementException

object Client {

  var msgAcc = ""

  def main(args: Array[String]): Unit = {
    val conn = new ClientConnection(InetAddress.getByName(args(0)), args(1).toInt)
    val server = conn.connect()
    println("Enter a username")
    val user = new User(StdIn.readLine())
    println("Welcome to the chat " + user.username)
    sys.addShutdownHook(this.shutdown(conn, server))
    new Thread(conn).start()
    while (true) {
    val tx = conn.tx
    if (tx != null) {
      conn.sendMsg(server, user, tx)
      val rxMsg = conn.getMsg(server)
      val parser = new JsonParser(rxMsg)
      val formattedMsg = parser.formatMsg(parser.toJson()) 
      println(formattedMsg)
      msgAcc = msgAcc + formattedMsg + "\n" 
      }
    }
  }

  def shutdown(conn: ClientConnection, server: Socket): Unit = {
    conn.close(server)
    val fileWriter = new BufferedWriter(new FileWriter(new File("history.txt"), true))
    fileWriter.write(msgAcc) 
    fileWriter.close()
</code></pre>

<p>This is the ClientConnection class extending Runnable:</p>

<pre><code>import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.SocketFactory
import java.net.Socket
import java.net.InetAddress
import java.net.InetSocketAddress
import java.security._
import java.io._
import scala.io._
import java.util.GregorianCalendar
import java.util.Calendar
import java.util.Date
import com.sun.net.ssl.internal.ssl.Provider
import scala.util.parsing.json._

class ClientConnection(host: InetAddress, port: Int) extends Runnable {

  var tx: String = null

  override def run(): Unit = {
     tx = StdIn.readLine()
  }

  def connect(): Socket = {
    Security.addProvider(new Provider())
    val sslFactory = SSLSocketFactory.getDefault()
    val sslSocket = sslFactory.createSocket(host, port).asInstanceOf[SSLSocket]
    sslSocket
   }

  def getMsg(server: Socket): String = new BufferedSource(server.getInputStream()).getLines().next()

  def sendMsg(server: Socket, user: User, msg: String): Unit = {
    val out = new PrintStream(server.getOutputStream())
    out.println(this.toMinifiedJson(user.username, msg))
    out.flush()
  }  

  private def toMinifiedJson(user: String, msg: String): String = {
    s"""{"time":"${this.getTime()}","username":"$user","msg":"$msg"}"""
  }

  private def getTime(): String = {
    val cal = Calendar.getInstance()
    cal.setTime(new Date())
    "(" + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND) + ")"
  }

  def close(server: Socket): Unit = server.close()
}
</code></pre>