I'm currently building an accounting app, now I want to persist this "Period End Date" that is changeable. I believe we can use global variable, however I don't know how to do so. What I have tried so far is to create a variable in application.conf like this application.date="2014/12/15".
Moreover, I'm not sure how to change the value using above approach . Is there any good approach for this problem ?
A possible way to go is to use a Singeleton Object which is initialized in the Global.scala.
The Global Object has to go in the scala-root of the application or to be configured through application.conf.
Singleton for shared Data
in app/shared/Shared.scala(the name is free)
package shared
object Shared {
private var data: Int = 0
def setData(d: Int) : Unit = data = 0
def getData : Int = data
}
In application.conf you can set the Global to be called on start of the application (you could also just put a file called Global.scala in app, that would be used by default)
application.global= settings.Global
shared.initial = 42
In app/settings/Global.scala
object Global extends GlobalSettings {
override def onStart(app: Application) {
// Here I use typesafe config to get config data out of application conf
val cfg: Config = ConfigFactory.load()
val initialValue = cfg.getInt(shared.initial)
// set initial value for shared
Shared.setData(initialValue)
}
}
In Play code to get or set the shared data.
import shared.Shared
Shared.getData
Shared.setData( 8 )
Related
After migrating from scala.js 0.6.x to 1.0, I've got some code related to #JSGlobalScope broken.
My use case is like this:
there's a 3rd-party library that expects some global var to be set to a function
when loaded and ready, it calls this function (by name)
I set this function in global scope from scala.js
The code looks like this:
#js.native
#JSGlobalScope
object Globals extends js.Object {
var callbackFunctionFor3rdPartyLib: js.Function0[Unit] = js.native
}
then I set this var like this:
Globals.callbackFunctionFor3rdPartyLib = () => {
// do things
}
and then I add the script into the DOM.
This was working with scala.js 0.6.x, but with 1.0 I'm getting an exception like the following:
scala.scalajs.js.JavaScriptException: ReferenceError: callbackFunctionFor3rdPartyLib is not defined
In the changelog for 1.0.0 there's a "Breaking changes" section that mentions this:
Accessing a member that is not declared causes a ReferenceError to be thrown
...
js.Dynamic.global.globalVarThatDoesNotExist = 42
would previously create said global variable. In Scala.js 1.x, it also throws a ReferenceError.
My question is:
what is the right way to do something like this (create a new global var) in scala.js 1.0?
If you know you'll always be in a browser context, you can use #JSGlobal("window") instead of #JSGlobalScope on your Globals, which will then be equivalent to doing window.myGlobalVarFor3rdPartyLib in JS. So that will work.
#js.native
#JSGlobal("window")
object Globals extends js.Object {
var callbackFunctionFor3rdPartyLib: js.Function0[Unit] = js.native
}
If not, but you are using a script (so not a CommonJS nor an ES module), the best thing is actually to use
object Globals {
#JSExportTopLevel("myGlobalVarFor3rdPartyLib")
var foo: js.Function[Unit] = ...
}
Note that Globals is a normal Scala object now, not a JS one.
The #JSExportTopLevel creates a top-level var myGlobalVarFor3rdPartyLib at the top of the script, and then assigning Globals.foo will also assign that top-level var.
If you're not using a script nor know that you're going to always be in a browser, then you need to figure out the global object yourself. Scala.js 0.6.x tried to do that for you, but could fail, so we don't do that anymore. You can at least follow the "instructions" on the documentation of js.special.fileLevelThis to reproduce what Scala.js 0.6.x was doing. I repeat the instructions here:
Using this value should be rare, and mostly limited to writing code
detecting what the global object is. For example, a typical detection
code--in case we do not need to worry of ES modules--looks like:
val globalObject = {
import js.Dynamic.{global => g}
if (js.typeOf(g.global) != "undefined" && (g.global.Object eq g.Object)) {
// Node.js environment detected
g.global
} else {
// In all other well-known environment, we can use the global `this`
js.special.fileLevelThis
}
}
Note that the above code is not comprehensive, as there can be JavaScript
environments where the global object cannot be fetched neither through
global nor this. If your code needs to run in such an environment, it
is up to you to use an appropriate detection procedure.
I need to create global JS variable in my Scala js.
How this can be done?
Via Facade Type
Make an object that extends js.GlobalScope:
object MyGlobal extends js.GlobalScope {
var globalVar: String
}
Then, just assign to it:
MyGlobal.globalVar = "foo"
Via Dynamic interface
js.Dynamic.global.globalVar = "foo"
Caveat
Both of these methods need code to be executed before the variable is set to anything. There is currently no way to directly export a top-level value in Scala.js without executing code (see #1381).
If you want to export the g shortcut:
import scala.scalajs.js
import js.Dynamic.{ global => g }
g.myVar = "foo"
I am making a multiplayer game client with ScalaFX GUI and Akka remoting for networking. When my client receives game data it stores it inside Model.gameData. I need my GUI to respond to this variable change.
I used gameData to create data:ObjectProperty in my Model object:
object Model {
var gameData:Option[GameData] = None
val data = new ObjectProperty(this,"data",Model.gameData)
...
}
drawGrid and drawPlayer are methods I use to update the GUI, located in CleintGUI object. I tired using addListener and onChange, they compile but the methods I placed inside of them are never invoked.
object ClientGUI extends JFXApp{
...
Model.data.addListener{ (o: javafx.beans.value.ObservableValue[_ <:Option[GameData]], oldVal: Option[GameData], newVal: Option[GameData]) =>
drawGrid
drawPlayer
}
Model.data onChange {
drawGrid
drawPlayer
}
}
What am I missing? Am I declaring data:ObectProperty or methods inside my ClientGUI incorrectly?
drawGrid and drawPlayer both work when I call them manually by creating an event through submitting a string in a TextField. When I receive GameData I also tried to directly call drawGrid and drawPlayer form inside of my actor class, but I got an error "Not an FX thread".
Edit: I got the GUI to update by mutating control attributes. However, ideally I would want to define the control attributes by using conditional expressions:
val data = new BooleanProperty(this,"data",Model.gameData.isDefined)
val msgLabel = new Label{
text <== when(data) choose " " otherwise "No GameData"
}
But this doesn't work as I can't figure out a way to define BooleanProperty such that when(data) changes value depending on boolean Model.gameData.isDefined
I was adding new elements to the GUI when I received gameData, by using GridPane.add method.
Instead of doing that I added all the controls(gui nodes/elements) during object creation and then changed their relevant attributes when I receive gameData.
e.g. I set Label.text from "No Game Data" to an empty string when I receive gameData:
def update {
ClientGUI.msgLabel = " "
}
I don't think this is the best approach as now I have publicly available vars in a multi threaded application, but since I only change them from one place when I receive new data it should be fine.
Ideally I would want to define the control attributes by using conditional expressions:
val data = new BooleanProperty(this,"data",Model.gameData.isDefined)
val msgLabel = new Label{
text <== when(data) choose " " otherwise "No GameData"
}
But this doesn't work as I can't figure out a way to define BooleanProperty such that when(data) changes value depending on boolean Model.gameData.isDefined
I would like to use Typesafe's Config in my project but I don't want any passwords in clear text in any file on the file system of any integration or production server. Also, I do not want to use environment variables to store clear text passwords.
Ideally, I would like a solution similar to the Jasypt EncryptablePropertyPlaceholderConfigurer available for Spring that would allow me to designate some property values as being encrypted and have the config system automatically decrypt them before handing the value down to the application. I'd like to use the JCE keystore to store the key and pass it into my app, but I'm also open to other tools that use a database to store keys.
Has anyone managed to get the Typesafe Config project to work this way?
Update: sourcedelica was completely correct to criticize the solution that relied on passing the key as an environment variable. I changed my question to request a solution that uses a more secure way of handling keys.
You could try pimping the typesafe Config class like so:
object ConfigPimping{
implicit class RichConfig(conf:Config){
def getPasswordString(path:String, encryptKey:String):String = {
val encrypted = conf.getString(path)
val decrypted = ... //do decripy logic of your choice here
decrypted
}
}
}
object ConfigTest{
import ConfigPimping._
def main(args: Array[String]) {
val conf = ConfigFactory.load()
val myPass = conf.getPasswordString("myPass", "myDecryptKey")
}
}
Then, as long as the RichConfig is always imported and available, you can get access to your custom decrpyt logic for passwords via the getPasswordString function.
If you are happy to pass the encryption key as an environment variable then instead you could pass all of the sensitive properties as environment variables and not worry about using encryption directly with the Typesafe config library.
For example:
my.sensitive = ${FOO_ENV}
You said that you do not want to use environment variables to store clear text passwords, but if you are storing your encryption key in an environment variable it is the equivalent.
Alternatively you could use a system property instead of an environment variable. For example, when starting your app, use -Dmy.sensitive=xxx.
If you do end up getting encrypted values into your configuration then you could use a wrapper class to that would do the decryption. I use a wrapper class to add methods like optString to Config. You could add a method like decryptString.
For a discussion on securing keys to be used in production see my question: Securing passwords in production environment.
I chose the path that cmbaxter suggested. I'm putting the example code here because comments don't seem to support code.
I added some special syntax, to the config file, so if I want to put an encrypted password in my config file I do it like this:
my-app-config{
db-username="foo"
db-password="ENC(9yYqENpuCkkL6gpoVh7a11l1IFgZ0LovX2MBF9jn3+VD0divs8TLRA==)"
}
Note the "ENC()" wrapper around the encrypted password.
Then I made a config factory that returns a DycryptingConfig object instead of the typesafe config:
import rzrelyea.config.crypto.DecryptingConfig;
import rzrelyea.config.crypto.KeyProvider;
public class ConfigFactory{
public static final Config makeDecryptingConfig(com.typesafe.config.Config config, KeyProvider keyProvider){
return new DecryptingConfig(config, keyProvider);
}
}
And here's the code for the DecryptingConfig:
import java.security.Key;
import static rzrelyea.config.Validators.require;
public class DecryptingConfig extends rzrelyae.config.Config {
private final com.typesafe.config.Config config;
private final Decryptor decryptor;
public DecryptingConfig(com.typesafe.config.Config config, KeyProvider keyProvider){
super(config);
require(keyProvider, "You must initialize DecryptingConfig with a non-null keyProvider");
this.config = config;
final Key key = keyProvider.getKey();
require(key, "KeyProvider must provide a non-null key");
decryptor = new Decryptor(config.getString("crypto-algorithm"), key, config.getString("encoding-charset"));
}
#Override
public String getString(String s) {
final String raw = config.getString(s);
if (EncryptedPropertyUtil.isEncryptedValue(raw)){
return decryptor.decrypt(EncryptedPropertyUtil.getInnerEncryptedValue(raw));
}
return raw;
}
Obviously, you'd need to implement your own rzrelyea.config.Config object, your own EncryptedPropertyUtil, your own Decryptor, and your own KeyProvider. My implementation of rzrelya.config.Config takes a typesafe config object as a constructor parameter and forwards all calls to it. LOTS of boiler plate code in it! But I thought it was better to forward calls to an interface rather than to extend com.typesafe.config.impl.SimpleConfig. You know, prefer composition to inheritance and code to interfaces, not implementations. You may choose a different route.
At the risk of telling you something you already know...
Never store a password -- store and compare against a hash instead
Use Bcrypt for password hashes -- it's slow which is good for guarding against a brute-force attack
Use a salt -- to guard against a rainbow table style attack
Use SSL (https) -- to prevent passwords from being seen in the clear
Here is an example that uses the Mindrot jBCrypt library:
def PasswordHash( name:String, pwd:String, version:Int = 1 ) : String = {
if( version == 2 && false )
{
// ANY CHANGES SHOULD BE MADE AS A NEW VERSION AND ADDED HERE
""
}
else
{
import org.mindrot.jbcrypt.BCrypt // jbcrypt-0.3m.jar
// Salt will be incorporated in the password hash
val salt = BCrypt.gensalt(12) // Default is 10, or 2**10 rounds. More rounds is slower.
BCrypt.hashpw( (name + pwd), salt )
}
}
def VerifyPassword( name:String, pwd:String, hash:String, version:Int = 1 ) : Boolean = {
if( version == 1 )
{
import org.mindrot.jbcrypt.BCrypt // jbcrypt-0.3m.jar
BCrypt.checkpw( (name + pwd), hash )
}
else
false
}
> PasswordHash( "johnny", "mypassword" )
res4: String = $2a$12$dHIlTL14.t37Egf7DqG4qePE446GzzhIUAVuewMfkhfK0xxw3NW6i
> VerifyPassword( "johnny", "mypassword", "$2a$12$dHIlTL14.t37Egf7DqG4qePE446GzzhIUAVuewMfkhfK0xxw3NW6i" )
res5: Boolean = true
> VerifyPassword( "johnny", "mommiespassword", "$2a$12$dHIlTL14.t37Egf7DqG4qePE446GzzhIUAVuewMfkhfK0xxw3NW6i" )
res6: Boolean = false
For what you are trying to do, I presume you would store the "name", "password hash", and "hash version" in your configuration.
I'm trying to create a restful method to update data in the database, I'm using Scala on Play! framework. I have a model called Application, and I want to be able to update an application in the database. So the put request only requires the id of the application you want to update, then the optional properties you want to update.
So in my routes I have this:
PUT /v1/auth/application controllers.Auth.update_application(id: Long)
The method I currently have is this:
def update_application(id: Long) = Action { implicit request =>
var app = Application.find(id)
for((key, value) <- request.queryString) {
app."$key" = value(0)
//app.name = value(0)
}
val update = Application.update(id, app)
Ok(generate(
Map(
"status" -> "success",
"data" -> update
)
)).as("application/json")
}
In the method above I am looping through the request and the app object as a map instance, then updating the app model to be updated using the model. I know there is an easier way is to create the request string as map and just iterate through the object, but I am doing it this way for learning purposes. I'm new to Play! and Scala, barely a week new.
Is there a way to set a property using a variable dynamically that way? In the above method at the end of the loop that is how I would update a object's property in Groovy. So I'm looking for the equivalent in Scala. If Scala can't do this, what is the best way about going about accomplishing this task? Reflection? I don't want to over-complicate things
Play! provides play.api.data.Forms which allows creating a Form that uses the apply() and unapply() methods of a case class. Then you can call form.fill(app) to create a form with the initial state, bindFromRequest(request) to update the form with the request parameters, and get() to obtain a new instance with updated fields.
Define the form only once:
val appForm = Form(
mapping(
"field1" -> text,
"field2" -> number
)(Application.apply)(Application.unapply)
)
Then in your controller:
val app = appForm.fill(Application.find(id)).bindFromRequest(request).get
val update = Application.update(id, app)
Check out Constructing complex objects from the documentation.