tags:

views:

176

answers:

2

I have a problem with my understanding of the standard actor library in Scala. In the code below I have created a simple swing, which basically should test if it is able to connect to a postgreSQL server. However it doesnt make it that far, I use Actors since the UI otherwise would freeze up while doing the work needed to connect to the database. When er i use this line (meaning that I use actors instead of a single thread)

PostgresCheck ! new GetInfo()

The Swing will never be updated. However if I comment the line out and use the next three lines. (meaning the actors wont be used)

      val result = PostgresCheck.checkPostgreSQL
      if (result == "OK") pgText.background = GREEN else pgText.background = RED
      pgText.text = result

The Swing will freeze but after about 25 seconds the swing will be updated.

import dbc.Database
import dbc.vendor.PostgreSQL
import java.awt.Dimension
import java.net.URI
import java.sql.Connection
import swing.event._
import swing._
import actors.Actor
import java.awt.Color._
import scala.actors.Actor._

case class Info(reply: String)
case class GetInfo()

object Example extends SimpleSwingApplication {
  val pgButton = new Button("Check PostgreSQL")
  val pgText = new TextArea("Not Checked Yet")
  val pgPanel = new GridPanel(1, 2)
  pgPanel.contents += pgButton
  pgPanel.contents += pgText

  def top = new MainFrame {
    title = "StateChecker"
    contents = pgPanel
  }

  listenTo(pgButton)
  reactions += {
    case e: ButtonClicked if (e.source.eq(pgButton)) => {
      PostgresCheck ! new GetInfo()

      //val result = PostgresCheck.checkPostgreSQL
      //if (result == "OK") pgText.background = GREEN else pgText.background = RED
      //pgText.text = result
    }
  }

  val guiActor = new Actor {
    def act() = {
      loop {
        react {
          case e: String => {
            val result = e
            if (result == "OK") pgText.background = GREEN else pgText.background = RED
            pgText.text = result
          }
          case e => println(e.toString)
        }
      }
    }
  }
  guiActor.start
}

object PostgresCheck extends Actor {
  def checkPostgreSQL() = {
    try {
      val db = new Database(myPgSQL)
      val con: Connection = myPgSQL.getConnection // Freezes while doing this method
      val statement = con.createStatement
      if (statement.getResultSet.getMetaData.getColumnCount == 1) "OK"
      else statement.getWarnings.toString
    }
    catch {
      case e => e.toString
    }
  }

  def act() = {
    loop {
      react {
        case e: GetInfo => {
          sender ! new Info(checkPostgreSQL)
        }
      }
    }
  }
  start()
}

object myPgSQL extends PostgreSQL {
  val uri = new URI("jdbc:postgresql://whatever.com")
  val user = "1234"
  val pass = "1234"
}
+2  A: 

You are sending the message outside an actor, it seems. Try this:

Actor.actor { PostgresCheck ! new GetInfo() }

Not sure if it will help, but it is standard advise.

And, now that I think of it, to whom will the answer be sent? You are replying to the non-existent sender. I suppose you want the answer going to guiActor, but I don't see you doing so.

Daniel
I doesn't make a difference if I use your suggested way. The GUI Event thread just create a message and put it into the queue, so it shouldnt make any difference.Nice spot i didn't notice that I send the reply to the wrong place, 'sender' should be replaced with 'Example.guiActor'.
Stefan
+1  A: 

Okay here we go, the problem was related to the line

sender ! new Info(checkPostgreSQL)

It should actually have been

Example.guiActor! new Info(checkPostgreSQL)

For some reason related to the Actor library it actually suspends when waiting for the database connection, and wont return because of an unknown sender. For instance the following lines result in a printout of just a single line in console with "1".

      val db = new Database(myPgSQL)
      println("1")
      // Freezes while doing this method
      val con: Connection = myPgSQL.getConnection 
      println("2")

When changing the mentioned line, the code behave as expected.

Stefan