I want to represent the data I have in a Tree and show it using TreeTableView. The items shown are wrapped in a case class:
case class Foo(name: StringProperty, desc:StringPropert) {
def this(_name: String, _desc: String) = this(StringProperty(_name), StringProperty(_dest))
}
Populating the tree is done asynchronously (calling an external program which takes time) via (basically):
val runner = Future {
// run command
}
runner onComplete {
case Success(ret) => // parse ret and update TreeTableView somehow
...
}
Since this is done async, I started with an empty node for the tree:
val ViewPkgs = new TreeItem[Foo](new Foo("root", "desc"))
...
val ViewTable = new TreeTableView[Foo](ViewPkgs) { columns ++= ... }
How do I update the list of packages from the async call above?
What I tried is creating a
val ViewBuf = ObservableBuffer[Foo]()
ViewPkgs.children = ObservableBuffer( ViewBuf.map { p => new TreeItem[Foo](p) } )
but that didn't help.
Thanks for any suggestions.
Related
I need to access this data mapData from Calculation.scala. The way I call the function in Final.scala is as seen below.
When I see the output of fetch_data() or print it I see Future(< not completed >) and result is empty. I do not know how to wait until all data is downloaded and then access mapData? MAy I know how to do it? I am new to scala. In C++ I am aware of callbacks and handling is easy there. But in scala I a using Future, Await or OnComplete, but not clear how to do it.
Final.Scala
object finalComputation {
val calculationInfo = new Calculaton()
calclulationInfo.fetch_data()
val result = calculationInfo.getMapData()
def main(args: Array[String]): Unit = {
........
}
}
Calculation.scala
class Calculation {
var mapData = Map.empty[String, String]
def createMapData(metricItem: ActualMetrics) = {
mapData += (metricItem._1 -> metricItem._2)
}
def getMapData() = {
mapData
}
def fetch_data() = {
val totalData: Future[Done] =
querApi
.getData()
.map { data =>
(data)
}
}
}
Await.result(totalData, Duration.Inf).runForeach(unit => {
createMapData(parse.From(totalData))
})
}
}
Well, by starter don't mix concurrency with mutability.
Second, don't create imperative APIs that require some specific call order.
Third, Future is just a fancy wrapper over callbacks.
And fourth, don't initiate computations before the main
// file: Calculation.scala
class Calculation(queryApi: Api) {
def fetchData(): Future[Map[String, String]] =
querApi.getData().map { data =>
data.view.map { metric =>
val ActualMetrics(key, value) = parse(metric)
key -> value
}.toMap
}
}
// file: Main.scala
object Main {
def main(args: Array[String]): Unit = {
val calculation = new Calculation(...)
val dataF = calculation.fetchData()
val result = dataF.map { data =>
// Here you can process the fetched data
// It may be flatMap or foreach, instead of map;
// depending on what you want to do, check the Scaladoc
}
// I don't use future, but I think here you need to do a final await of result.
// In order to avoid the program to finish before the async computation.
}
}
I had to assume some types, but I hope this gives you a general idea of what to do.
My advice, pick any Scala course / book / tutorial and properly learn the language.
I am trying to build a multi level Validator object that is fairly generic. The idea being you have levels of validations if Level 1 passes then you do Level 2, etc. but I am struggling with one specific area: creating a function call but not executing it until a later point.
Data:
case class FooData(alpha: String, beta: String) extends AllData
case class BarData(gamma: Int, delta: Int) extends AllData
ValidationError:
case class ValidationError(code: String, message: String)
Validator:
object Validator {
def validate(validations: List[List[Validation]]): List[ValidationError] = {
validations match {
case head :: nil => // Execute the functions and get the results back
// Recursively work down the levels (below syntax may be incorrect)
case head :: tail => validate(head) ... // if no errors then validate(tail) etc.
...
}
}
}
Sample Validator:
object CorrectNameFormatValidator extends Validation {
def validate(str: String): Seq[ValidationError] = {
...
}
}
How I wish to use it:
object App {
def main(args: Array[String]): Unit = {
val fooData = FooData(alpha = "first", beta = "second")
val levelOneValidations = List(
CorrectNameFormatValidator(fooData.alpha),
CorrectNameFormatValidator(fooData.beta),
SomeOtherValidator(fooData.beta)
)
// I don't want these to execute as function calls here
val levelTwoValidations = List(
SomeLevelTwoValidator (fooData.alpha),
SomeLevelTwoValidator(fooData.beta),
SomeOtherLevelValidator(fooData.beta),
SomeOtherLevelValidator(fooData.alpha)
)
val validationLevels = List(levelOneValidations, levelTwoValidations)
Validator.validate(validationLevels)
}
}
Am I doing something really convoluted when I don't need to be or am I just missing a component?
Essentially I want to define when a function will be called and with which parameters but I don't want the call to happen until I say within the Validator. Is this something that's possible?
You can use lazy val or def when defining levelOneValidation, levelTwoValidations and validationLevel:
object App {
def main(args: Array[String]): Unit = {
val fooData = FooData(alpha = "first", beta = "second")
lazy val levelOneValidations = List(
CorrectNameFormatValidator(fooData.alpha),
CorrectNameFormatValidator(fooData.beta),
SomeOtherValidator(fooData.beta)
)
// I don't want these to execute as function calls here
lazy val levelTwoValidations = List(
SomeLevelTwoValidator (fooData.alpha),
SomeLevelTwoValidator(fooData.beta),
SomeOtherLevelValidator(fooData.beta),
SomeOtherLevelValidator(fooData.alpha)
)
lazy val validationLevels = List(levelOneValidations, levelTwoValidations)
Validator.validate(validationLevels)
}
}
You also need to change validate method to get the validations ByName and not
ByValue using : => :
object Validator {
def validate(validations: => List[List[Validation]]): List[ValidationError] = {
validations match {
case head :: nil => // Execute the functions and get the results back
// Recursively work down the levels (below syntax may be incorrect)
case head :: tail => validate(head) ... // if no errors then validate(tail) etc.
...
}
}
}
Anyway, I think you can implement it differently by just using some OOP design patterns, like Chain of Responsibility.
In my particular case I have a menu that is rendered on all pages. The menu content is loaded from a database using slick and passed implicitly to the view. The whole thing looks like this:
Controller
class Application #Inject()(
implicit val menuContext: MenuContext
) extends Controller {
def index = Action.async {
val content: Future[Content] = getContent
content.map(c => Ok(views.html.index(c)))
}
}
MenuContext
class MenuContext {
val models: Future[List[SomeModel]] = getModelsFromDB
}
View
#(content: Content)(implicit menuContext: MenuContext)
...
#menuContext.models // how to access my actual model and not the Future?
...
How do I access List[SomeModel] in my view? Is there an Action.async equivalent in play for passing implicit parameters? Or is there maybe even a better solution for stuff that is required in (almost) all views?
Definitely not a good idea to make a template have to deal with a Future - so the question becomes the one in your comment - how to non-blockingly (?) get the content from your async content source, as well as your menu items from your other async content source?
A for-comprehension on the two Future instances does the trick:
def index = Action.async {
val fContent:Future[Content] = getContent
val fMenus:Future[List[SomeModel] = getModelsFromDB
for {
content <- fContent
menus <- fMenus
} yield(Ok(views.html.index(content)(menus))))
}
Note: You may be tempted to try and save a few lines and put the method calls (getContent, getModelsFromDB) straight into the for block.
Unfortunately, while it'll compile and work, the two tasks won't run in parallel, thereby making the exercise somewhat futile.
OK I'm adding another answer here, to specifically try to DRY up the injection of menus into your Actions.
The principal problem is that you need to inject the menus at just the right time, namely:
When you have the data ready (or at least a Future holding the data)
When you know which template is going to be rendered
When you know what status code you'll be returning
Because of these constraints, we can't use an ActionBuilder or ActionRefiner - they assume that your inner block of controller code will produce a finished Result.
So instead, we'll define a trait we can mix into our controllers:
trait MenuDecoration {
def withMenuSimple(body: Future[List[SomeModel] => Result]):Future[Result] = {
val fm = getModelsFromDB
val fb = body
for {
m <- fm
b <- fb
} yield(b(m))
}
}
This should look pretty familiar from my other answer, and it works the same way - it will start the execution of both async tasks, bringing them together once they are both done.
An Action that needs to decorate the template with a menu looks like this:
class BlahController extends Controller with MenuDecoration {
def index = Action.async {
withMenuSimple {
getContent.map { content => implicit menu =>
Ok(views.html.index(content))
}
}
}
}
Why withMenuSimple ? Because at some point you'll probably want to examine the Request - so we have this alternative:
trait MenuDecoration {
...
def withMenu(body: RequestHeader => Future[List[SomeModel] => Result])(implicit request:RequestHeader):Future[Result] = {
val fm = fMenus
val fb = body(request)
for {
m <- fm
b <- fb
} yield(b(m))
}
}
which you'd use like this:
def indexWithReq = Action.async { implicit request =>
withMenu { req =>
getContent.map { content => implicit menu =>
Ok(views.html.index(content))
}
}
}
I am writing a Play (2.2) controller in Scala, which should return the result of a query against OrientDB. Now, I have succeeded in writing a synchronous version of said controller, but I'd like to re-write it to work asynchronously.
My question is; given the below code (just put together for demonstration purposes), how do I re-write my controller to interact asynchronously with OrientDB (connecting and querying)?
import play.api.mvc.{Action, Controller}
import play.api.libs.json._
import com.orientechnologies.orient.`object`.db.OObjectDatabasePool
import java.util
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery
import scala.collection.JavaConverters._
object Packages extends Controller {
def packages() = Action { implicit request =>
val db = OObjectDatabasePool.global().acquire("http://localhost:2480", "reader", "reader")
try {
db.getEntityManager().registerEntityClass(classOf[models.Package])
val packages = db.query[util.List[models.Package]](new OSQLSynchQuery[models.Package]("select from Package")).asScala.toSeq
Ok(Json.obj(
"packages" -> Json.toJson(packages)
))
}
finally {
db.close()
}
}
}
EDIT:
Specifically, I wish to use OrientDB's asynchronous API. I know that asynchronous queries are supported by the API, though I'm not sure if you can connect asynchronously as well.
Attempted Solution
Based on Jean's answer, I've tried the following asynchronous implementation, but it fails due to a compilation error value execute is not a member of Nothing possible cause: maybe a semicolon is missing before 'value execute'?:
def getPackages(): Future[Seq[models.Package]] = {
val db = openDb
try {
val p = promise[Seq[models.Package]]
val f = p.future
db.command(
new OSQLAsynchQuery[ODocument]("select from Package",
new OCommandResultListener() {
var acc = List[ODocument]()
#Override
def result(iRecord: Any): Boolean = {
val doc = iRecord.asInstanceOf[ODocument]
acc = doc :: acc
true
}
#Override
def end() {
// This is just a dummy
p.success(Seq[models.Package]())
}
// Fails
})).execute()
f
}
finally {
db.close()
}
}
One way could be to start a promise, return the future representing the result of that promise, locally accumulate the results as they come and complete de promise ( thus resolving the future ) when orient db notifies you that the command has completed.
def executeAsync(osql: String, params: Map[String, String] = Map()): Future[List[ODocument]] = {
import scala.concurrent._
val p = promise[List[ODocument]]
val f =p.future
val req: OCommandRequest = database.command(
new OSQLAsynchQuery[ODocument]("select * from animal where name = 'Gipsy'",
new OCommandResultListener() {
var acc = List[ODocument]()
#Override
def result(iRecord:Any):Boolean= {
val doc = iRecord.asInstanceOf[ODocument]
acc=doc::acc
true
}
#Override
def end() {
p.success(acc)
}
}))
req.execute()
f
}
Be careful though, to enable graph navigation and field lazy loading, orientdb objects used to keep an internal reference to the database instance they were loaded from ( or to depend on a threadlocal database connected instance ) for lazily loading elements from the database. Manipulating these objects asynchronously may result in loading errors. I haven't checked changes from 1.6 but that seemed to be deeply embedded in the design.
It's as simple as wrapping the blocking call in a Future.
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scala.concurrent.Future
object Packages extends Controller {
def packages = Action.async { implicit request =>
val db = OObjectDatabasePool.global().acquire("http://localhost:2480", "reader", "reader")
db.getEntityManager().registerEntityClass(classOf[models.Package])
val futureResult: Future[Result] = Future(
db.query[util.List[models.Package]](new OSQLSynchQuery[models.Package]("select from Package")).asScala.toSeq
).map(
queryResult => Ok(Json.obj("packages" -> Json.toJson(packages)))
).recover {
// Handle each of the exception cases legitimately
case e: UnsupportedOperationException => UnsupportedMediaType(e.getMessage)
case e: MappingException => BadRequest(e.getMessage)
case e: MyServiceException => ServiceUnavailable(e.toString)
case e: Throwable => InternalServerError(e.toString + "\n" + e.getStackTraceString)
}
futureResult.onComplete { case _ =>
db.close()
}
futureResult
}
}
Note that I did not compile the code. There is a lot of room to improve the code.
My current application is based on akka 1.1. It has multiple ProjectAnalysisActors each responsible for handling analysis tasks for a specific project. The analysis is started when such an actor receives a generic start message. After finishing one step it sends itself a message with the next step as long one is defined. The executing code basically looks as follows
sealed trait AnalysisEvent {
def run(project: Project): Future[Any]
def nextStep: AnalysisEvent = null
}
case class StartAnalysis() extends AnalysisEvent {
override def run ...
override def nextStep: AnalysisEvent = new FirstStep
}
case class FirstStep() extends AnalysisEvent {
override def run ...
override def nextStep: AnalysisEvent = new SecondStep
}
case class SecondStep() extends AnalysisEvent {
...
}
class ProjectAnalysisActor(project: Project) extends Actor {
def receive = {
case event: AnalysisEvent =>
val future = event.run(project)
future.onComplete { f =>
self ! event.nextStep
}
}
}
I have some difficulties how to implement my code for the run-methods for each analysis step. At the moment I create a new future within each run-method. Inside this future I send all follow-up messages into the different subsystems. Some of them are non-blocking fire-and-forget messages, but some of them return a result which should be stored before the next analysis step is started.
At the moment a typical run-method looks as follows
def run(project: Project): Future[Any] = {
Future {
progressActor ! typicalFireAndForget(project.name)
val calcResult = (calcActor1 !! doCalcMessage(project)).getOrElse(...)
val p: Project = ... // created updated project using calcResult
val result = (storage !! updateProjectInformation(p)).getOrElse(...)
result
}
}
Since those blocking messages should be avoided, I'm wondering if this is the right way. Does it make sense to use them in this use case or should I still avoid it? If so, what would be a proper solution?
Apparently the only purpose of the ProjectAnalysisActor is to chain future calls. Second, the runs methods seems also to wait on results to continue computations.
So I think you can try refactoring your code to use Future Composition, as explained here: http://akka.io/docs/akka/1.1/scala/futures.html
def run(project: Project): Future[Any] = {
progressActor ! typicalFireAndForget(project.name)
for(
calcResult <- calcActor1 !!! doCalcMessage(project);
p = ... // created updated project using calcResult
result <- storage !!! updateProjectInformation(p)
) yield (
result
)
}