Pass data to a ScalaFX JFXApp - scala

I wrote a GUI in ScalaFX whichs works quite well when testing it isolated. Things to mention:
The "real" application itself already has a main method, and only that one should be used to start the application, not the one I get when extending JFXApp. So the call to the main method of JFXApp is done manually, from the outside
It should be possible to pass a data structure to the JFXApp, so I added a setter
The whole startup procedure looks like this:
def main(args: Array[String]) {
...
...
JFXGui.setData(data)
JFXGui.main(Array())
}
The problem:
I cannot draw the contents of the data object as long as the main method of the JFX object is not called, so setData is really just a simple setter method. The idea is that JFXGui should draw the data as soon as possible after JFXGui.main was called. But: how can I realize this inside of JFXGui? Is there something like an "onready"-method?
In the above code, I tried to put the call to the setter after the call to the main method, so that the setter can trigger the drawing. What I hadn't in mind is that JFXGui.main is blocking forever, therefore the call to the setter is unreachable code.
How could I fix this? any help is appreciated, thanks.
edit:
JFXGui is the name of my ScalaFX UI:
object JFXGui extends JFXApp {
private var data: Data = _
def setData(data: Data) {
this.data = data;
}
// tons of ScalaFX related things which visualize the data object
// ...
}

Solution 1 (reusing JFXApp)
The Gui object no longer should be an object, but a class with constructor parameters.
class Gui(data: Data) extends JFXApp {
//your existing code without the field data and the method setData()
}
In the startup class:
new Gui(data).main(Array())
Solution 2 (Custom init)
You do not necessarily have to use JFXApp in order to run your application. I suggest you having a look at the source code of JFXApp.main() and the class AppHelper. They contain ~10 lines of code combined so you can just copy their source code and tailor it to your needs.

Related

ScalaFX - How to get the title of a Scene using a method

I am using ScalaFX and trying to learn how it works. As an exerpiment (not what I will do in production) I want a method that gets the title of a window.
So here is my Graph.scala file:
package graphing
import scalafx.application.JFXApp
import scalafx.scene.Scene
import scalafx.scene.paint.Color
class Graph {
val app = new JFXApp {
stage = new JFXApp.PrimaryStage {
title = "First GUI"
scene = new Scene {
fill = Color.Coral
}
}
}
def getTitle() = {
app.stage.getTitle
}
def generateChart(args: Array[String]) = app.main(args)
}
Here is my driver object that makes use of this Graph class:
package graphing
import graphing.Graph
object Driver extends App {
val graph = new Graph
println(graph.getTitle())
graph.generateChart(args)
}
However, this does not work due to the line
println(graph.getTitle())
The error that is thrown:
Could someone kindly explain what is going on and how I can achieve my goal here?
The problem here concerns JavaFX (and hence, ScalaFX) initialization.
Initializing JavaFX is a complex business. (Indeed, I only recently learned that it was even more complicated than I originally believed it to be. Refer to this recent answer here on StackOverflow for further background. Fortunately, your problem is a little easier to resolve.)
ScalaFX simplifies JavaFX initialization greatly, but requires that the JFXApp trait be used as part of the definition of an object.
JFXApp contains a main method, which must be the starting point of your application; it is this method that takes care of the complexities of initializing JavaFX for you.
In your example, you have your Driver object extend scala.App, and so it is App's (and hence, Driver's) main method that becomes the starting point of your own application. This is fine for a regular command line interface (CLI) application, but it cannot be used with ScalaFX/JavaFX applications without a great deal of additional complexity.
In your code, JFXApp's main method never executes, because, as it is defined as a class member, it is not the main method of a Scala object, and so is not a candidate for automatic execution by the JVM. You do call it manually from your Graph.generateChart() method, but that method itself is not called until after you try to get the title of the scene, hence the NPE as the stage has not yet been initialized.
What if you put the graph.generateChart(args) call before the println(graph.getTitle()) statement? Will that fix it? Sadly, no.
Here's why...
JFXApp also performs one other bit of magic: it executes the construction code for its object (and for any other classes extended by that object, but not for extended traits) on the JavaFX Application Thread (JAT). This is important: only code that executes on the JAT can interact directly with JavaFX (even if through ScalaFX). If you attempt to perform JavaFX operations on any other thread, including the application's main thread, then you will get exceptions.
(This magic relies on a deprecated Scala trait, scala.DelayedInit, which has been removed from the libraries for Scala 3.0, aka Dotty, so a different mechanism will be required in the future. However, it's worth reading the documentation for that trait for further background.)
So, when Driver's construction code calls graph.generateChart(args), it causes JavaFX to be initialized, starts the JAT, and executes Graph's construction code upon it. However, by the time Driver's constructor calls println(graph.getTitle()), which is still executing on the main thread, there are two problems:
Graph's construction code may, or may not, have been executed, as it is being executed on a different thread. (This problem is called a race condition, because there's a race between the main thread trying to call println(graph.getTitle()), and the JAT trying to initialize the graph instance.) You may win the race on some occasions, but you're going to lose quite often, too.
You're trying to interact with JavaFX from the main thread, instead of from the JAT.
Here is the recommended approach for your application to work:
package graphing
import scalafx.application.JFXApp
import scalafx.scene.Scene
import scalafx.scene.paint.Color
object GraphDriver
extends JFXApp {
// This executes at program startup, automatically, on the JAT.
stage = new JFXApp.PrimaryStage {
title = "First GUI"
scene = new Scene {
fill = Color.Coral
}
}
// Print the title. Works, because we're executing on the JAT. If we're NOT on the JAT,
// Then getTitle() would need to be called via scalafx.application.Platform.runLater().
println(getTitle())
// Retrieve the title of the stage. Should equal "First GUI".
//
// It's guaranteed that "stage" will be initialized and valid when called.
def getTitle() = stage.title.value
}
Note that I've combined your Graph class and Driver object into a single object, GraphDriver. While I'm not sure what your application needs to look like architecturally, this should be an OK starting point for you.
Note also that scala.App is not used at all.
Take care when calling GraphDriver.getTitle(): this code needs to execute on the JAT. The standard workaround for executing any code, that might be running on a different thread, is to pass it by name to scalafx.application.Platform.runLater(). For example:
import scalafx.application.Platform
// ...
Platform.runLater(println(ObjectDriver.getTitle()))
// ...

Scala: how to avoid passing the same object instance everywhere in the code

I have a complex project which reads configurations from a DB through the object ConfigAccessor which implements two basic APIs: getConfig(name: String) and storeConfig(c: Config).
Due to how the project is currently designed, almost every component needs to use the ConfigAccessor to talk with the DB. Thus, being this component an object it is easy to just import it and call its static methods.
Now I am trying to build some unit tests for the project in which the configurations are stored in a in-memory hashMap. So, first of all I decoupled the config accessor logic from its storage (using the cake pattern). In this way I can define my own ConfigDbComponent while testing
class ConfigAccessor {
this: ConfigDbComponent =>
...
The "problem" is that now ConfigAccessor is a class, which means I have to instantiate it at the beginning of my application and pass it everywhere to whoever needs it. The first way I can think of for passing this instance around would be through other components constructors. This would become quite verbose (adding a parameter to every constructor in the project).
What do you suggest me to do? Is there a way to use some design pattern to overcome this verbosity or some external mocking library would be more suitable for this?
Yes, the "right" way is passing it in constructors. You can reduce verbosity by providing a default argument:
class Foo(config: ConfigAccessor = ConfigAccessor) { ... }
There are some "dependency injection" frameworks, like guice or spring, built around this, but I won't go there, because I am not a fan.
You could also continue utilizing the cake pattern:
trait Configuration {
def config: ConfigAccessor
}
trait Foo { self: Configuration => ... }
class FooProd extends Foo with ProConfig
class FooTest extends Foo with TestConfig
Alternatively, use the "static setter". It minimizes changes to existing code, but requires mutable state, which is really frowned upon in scala:
object Config extends ConfigAccessor {
#volatile private var accessor: ConfigAccessor = _
def configurate(cfg: ConfigAccessor) = synchronized {
val old = accessor
accessor = cfg
old
}
def getConfig(c: String) = Option(accessor).fold(
throw new IllegalStateException("Not configurated!")
)(_.getConfig(c))
You can retain a global ConfigAccessor and allow selectable accessors like this:
object ConfigAccessor {
private lazy val accessor = GetConfigAccessor()
def getConfig(name: String) = accessor.getConfig(name)
...
}
For production builds you can put logic in GetConfigAccessor to select the appropriate accessor based on some global config such as typesafe config.
For unit testing you can have a different version of GetConfigAccessor for different test builds which return the appropriate test implementation.
Making this value lazy allows you to control the order of initialisation and if necessary do some non-functional mutable stuff in the initialisation code before creating the components.
Update following comments
The production code would have an implementation of GetConfigAccessor something like this:
object GetConfigAccessor {
private val useAws = System.getProperties.getProperty("accessor.aws") == "true"
def apply(): ConfigAccessor =
if (useAws) {
return new AwsConfigAccessor
} else {
return new PostgresConfigAccessor
}
}
Both AwsConfigAccessor and PostgresConfigAccessor would have their own unit tests to prove that they conform to the correct behaviour. The appropriate accessor can be selected at runtime by setting the appropriate system property.
For unit testing there would be a simpler implementation of GetConfigAccessor, something like this:
def GetConfigAccessor() = new MockConfigAccessor
Unit testing is done within a unit testing framework which contains a number of libraries and mock objects that are not part of the production code. These are built separately and are not compiled into the final product. So this version of GetConfigAccessor would be part of that unit testing code and would not be part of the final product.
Having said all that, I would only use this model for reading static configuration data because that keeps the code functional. The ConfigAccessor is just a convenient way to access global constants without having them passed down in the constructor.
If you are also writing data then this is more like a real DB than a configuration. In that case I would create custom accessors for each component that give access to different parts of the DB. That way it is clear which parts of the data are updated by each component. These accessors would be passed down to the component and can then be unit tested with the appropriate mock implementation as normal.
You may need to partition your data into static config and dynamic config and handle them separately.

How do I give global access to an object in Scala without making it a singleton or passing it to everything?

I have a Logger class that logs events in my application. While I only need one instance of the logger in this application, I want this class to be reusable, so I don't want to make it a singleton and couple it with my specific needs for this application.
I want to be able to access this Logger instance from anywhere in the application without having to create a new one every time or pass it around to every class that might need to log something. What I currently do is have an ApplicationUtils singleton that I use as the point of access for the application's Logger:
object ApplicationUtils {
lazy val log : Logger = new Logger()
}
Then I have a Loggable trait that I add to classes that need the Logger:
trait Loggable {
protected[this] lazy val log = ApplicationUtils.log
}
Is this a valid approach for what I am trying to accomplish? It feels a little hack-y. Is there a better approach I could be using? I'm pretty new to Scala.
Be careful when putting functionality in objects. That functionality is easily testable, but if you need to test clients of that code to make sure they interact with it correctly (via mocks and spies), you're stuck 'cause objects compile to final classes and thus cannot be mocked.
Instead, use this pattern:
trait T { /* code goes here */ }
object T extends T /* pass this to client code from main sources */
Now you can create Mockito mocks / spies for trait T in your test code, pass that in and confirm that the interactions of the code under test with the trait T code are what they should be.
If you have code that's a client of T and whose interactions with it don't require testing, you can directly reference object T.
To address what you're trying to do (rather than what you're asking), take a look at TypeSafe's scalalogging package. It provides a Logging trait that you can use like so:
class MyClass extends Logging {
logger.debug("This is very convenient ;-)")
}
It's a macro-based wrapper for SLF4J, so something like logger.debug(...) gets compiled as if (logger.isDebugEnabled) logger.debug(...).

How to re-boot liftweb?

I have my Boot.scala with boot method in it where i do my setup.
At the end, I make the call to LiftRules.statelessDispatchTable and append an new instance of my class that extends the RestHelper, which has the serve block.
At some point, I get a signal and need to change this class, so i need to make another call into the statelessDispatchTable to remove the original one and add a new one.
What's a good way to do this?
Thanks!
EDIT: I AM GOING TO UPDATE THE QUESTION WITH THE ANSWER I GOT FROM DAVID POLLAK:
You can't. Once your app is started, there's no way to change LiftRules.
However, the stuff you're adding to statelessDispatchTable is a PartialFunction[Req, Box[LiftResponse]] so you can write a PartialFunction that looks like:
object RestThing1 extends RestHelper { .... }
object RestThing2 extends RestHelper {....}
object MyDynamicRestThing extends PartialFunction[Req, Box[LiftResponse]] {
def isDefinedAt(in: Req): Boolean = if (testCondition) RestThing1.isDefinedAt(in) else RestThing2.isDefinedAt(in)
def apply(in: Req): Box[LiftRequest] = if (testCondition) RestThing1.apply(in) else RestThing2.apply(in)
}
LiftRules.statelessDispatchTable.append(MyDynamicRestThing)
You could create a second-level dispatch...e.g., an object that receives the requests, then according to some other logic proxies the requests on to the real handler. Then you don't have to mess with the top-level dispatch table at all.
Would really make sense to do this if what you are needing to do is toggle it based on a signal (e.g. it will revert back at some point), or if there is additional logic that would benefit from being in a proper abstraction.

Scala object struggles with Java Class.newInstance()

UPDATE:
I have somewhat resolved the issue. Just in case if anyone runs in the same problem, here is the simplest solution: Looking at the MTApplcation source code, I have discovered that the initialize() method can be overloaded, taking a String parameter for the name of the class to instantiate. So if I create a separate class that extends MTApplication and pass it's name there, everything works correctly.
END OF UPDATE
I have a situation in Scala while trying to use a java library (MT4j, which is based on Processing). The library wants to instantiate the main class of the app (the caller-class):
Class<?> c = Thread.currentThread().getContextClassLoader().loadClass(name);
applet = (PApplet) c.newInstance();
So as to refer it later in it's works.
However, it fails because, I guess, the main Scala class is not a class, but an object and due to library structure, it is necessary to call a static method initialize() of the main library class MTApplication. In Java static fields are located in classes, but in Scala - in objects. So it is impossible to instantiate an object and the library fails. In contrast to MT4j, Processing itself makes no calls to static methods on startup and successfully passes that phase.
If I just create a companion class, everything works fine except that the companion class does not get its fields initialized because the static initialize() method is called in companion object, the class instance just gets dead-born and the library becomes unusable.
At least that is how I understand this problem.
I get this error:
Exception in thread "main" java.lang.RuntimeException: java.lang.IllegalAccessException: Class processing.core.PApplet can not access a member of class main.Main$ with modifiers "private"
at processing.core.PApplet.runSketch(PApplet.java:9103)
at processing.core.PApplet.main(PApplet.java:9292)
at org.mt4j.MTApplication.initialize(MTApplication.java:311)
at org.mt4j.MTApplication.initialize(MTApplication.java:263)
at org.mt4j.MTApplication.initialize(MTApplication.java:254)
at main.Main$.main(Main.scala:26)
at main.Main.main(Main.scala)
It is hard for me to explain also because I do not fully understand what is going on here. But anyone who has these libs can reproduce the situation in a couple of minutes, trying to launch the main class.
The abstract startUp() method which should be implemented to start the app, makes everything look even more sad. It initializes the object, but what the library tries to work with is an instance of the companion class which does not get initialized because in Scala the method belongs to the object.
My code:
object Main extends MTApplication {
def main(args: Array[String]) {
MTApplication.initialize()
new Main().startUp()
}
//this method is abstarct so it MUST be implemented,
override def startUp(){
}
}
class Main extends MTApplication {
override def startUp(){
//startup here
}
}
I am sorry if my explanations are vague, I just do not get it all completely. Probably to understand it is easier to repeat the experiment with MT4j library with Processing source code instead of the pre-linked 'core.jar' there to see what is happening inside. Doeas anyone have ideas on any workaround here?
Problem solved. Here is the solution:
object Main {
var current: MainC = _
def main(args: Array[String]) {
MTApplication.initialize("org.mttablescreen.main.MainC")
}
}
class MainC extends MTApplication {
//cons
Main.current = this
//cons ends
override def startUp(){
prepare
}
def prepare () {...}
}