scala read the configs dynamically during run time - scala

I have a config file in the below folder subtract
main
scala
resources
application.conf
and that contains
path{
http{
url = "http://testingurl"
}
}
I am reading using below code
import com.typesafe.config.Config;
val url = conf.getString("path.http.url")
I am reading this static information which is provided durng build time.
Now I want to read these in runtime, user should be able to modify configs even after jar is built.
my requirement is to modify url event after jar is build, I dont want to pass as a arguments to the main function because I have so many such values which needs to modified after jar built

See:
Lightbend Config Readme
Use at runtime:
-Dconfig.file=<relative or absolute path>
See:
For applications using application.{conf,json,properties},
system properties can be used to force a different config source
(e.g. from command line -Dconfig.file=path/to/config-file):
config.resource specifies a resource name - not a basename, i.e. application.conf not application
config.file specifies a filesystem path, again it should include the extension, not be a basename
config.url specifies a URL
These system properties specify a replacement for application.{conf,json,properties}, not an addition.
They only affect apps using the default ConfigFactory.load() configuration.
In the replacement config file, you can use include "application" to include the original default config file;
after the include statement you could go on to override certain settings.

I assume that a .jar file is build with a key provided as
val url = conf.getString("path.http.url")
and you are going to run this .jar every time with modified .config file
my requirement is to modify url event after jar is build,
a possible solution is to provide a array of the config values, where key remains same in .jar file
import com.typesafe.config.ConfigFactory
ConfigFactory.load().getStringList("url.key").stream().map(eachUrl => functionToBeCalled)

Related

How to use different application.conf per environment in Akka-Http?

I am new in Akka and want to set up different application.conf files per environment (test, staging, prod, etc.).
I read the documentation from Akka but I couldn't find a way to do it.
May you know any proper way to have multiple configuration files?
Akka uses the Typesafe Config Library.
The convenience method ConfigFactory.load() loads the following (first-listed are higher priority):
system properties
application.conf (all resources on classpath with this name)
application.json (all resources on classpath with this name)
application.properties (all resources on classpath with this name)
reference.conf (all resources on classpath with this name)
So we usually create an application.conf file in /resources folder.
For different environments, we can create environment specific files like
development.conf
production.conf
Using includes, include application.conf at the beginning and specify environment specific configurations which will override the application.conf.
To use a specific environment force a different config source (e.g. from command line -Dconfig.resource=environment.conf)
Start your application using below command:
$ sbt run -Dconfig.resource=development.conf
Here are couple ways to do it.
Add tags with in a file itself like
prod-config : { YOUR_CONFIGURATION_FOR_PROD }
test-config : { YOUR_CONFIGURATION_TEST_ENV }
and so-on
Make separate files for the each environment and rename it once after deploying them to specific environment. Say from application-prod.conf to application.conf
A possibility is have a single variable in application.conf which would be "confFile", based on an actual env like
confFile=${?CONF_FILE_NAME}
Then in your code, you load the correspondind file like this
val configFile = ConfigFactory.load().getString("confFile")
val appConf = ConfigFactory.load(configFile)
The options for this aren't so much related to Akka as it is to the config library. Akka uses the default config resolution unless you give it a Config instance.
With no specific user code to manually select a specific file you have a few options. I think the most useful are the system properties config.resource to choose a file on the class path (inside the app jar for example), config.file to use a file from the file system.
Of course you may still have reasons to write your own code to select files as the other answers suggested.
More details in the config library docs: https://github.com/lightbend/config#standard-behavior

Play Framework - debug & release configurations?

When developing a Play application, we use the standard configuration file in conf/application.conf. How can I use different conf files depending on whether I'm in debug or release mode?
Let's say you have prod.conf and debug.conf both in the conf folder, you can add the following system property:
-Dconfig.resource=(prod|debug).conf
if the files can't be packaged in the app in the conf folder and have to be external, for example, in /opt/conf, then you can add the following instead:
-Dconfig.file=/opt/conf/(prod|debug).conf
They can inherit a common configuration file and override values:
include "application.conf"
key.to.override=blah
See reference for more on this.

sbt run - how to specify working directory? [duplicate]

I would like to be able to run the java program in a specific directory. I think, that it is quite convenient to parametrize working directory, because it allows to easily manage configurations.
For example in one folder you could have configuration for test, in other you could have resources needed for production. You probably think, that there is option to manipulate classpath for including/exluding resources but such solution works only if you are interested in resources stored in classpath and referencing them using Classloader.getResource(r). But what if you have some external configuration and you want to access it using simple instructions like File file = new File("app.properties");?
Let's see ordinary example.
Your application uses app.properties file, where you store credentials for external service. Application looks for this file in working directory, because you uses mentioned File file = new File("app.properties"); instruction to access it. In your tests you want to use app.properties specific to your tests. In you integration tests you want to use app.properties specific to another environment. And finally when you build and release application you want to provide other app.properties file. All these resources you want to access always in the same way just by typing File file = new File("app.properties"); instead of (pseudo code):
if(configTest)
file = File("testWorkDir/app.properties");
else if(config2)
file = File("config2WorkDir/app.properties");
else
file = File("app.properties");
or instead of using resources in classpath
this.getClass.getClassLoader.getResource("app.properties");
Of course you are clever programmer and you use build tool such maven, gradle or sbt :)
Enought at the outset. At least The Question:
Is there a way to set working directory in java and if yes how to configure it in build tools (especially in sbt)?
Additional info:
changing 'user.dir' system property is not working (I've tried to change it programaticly).
In sbt changing 'working directory' via baseDirectory setting for test changes baseDirectory which is not base dir in my understangind and it is not equal new java.io.File(".").getAbsolutePath.
Providing environment variable like YOUR_APP_HOME and referencing resources from this path is feasible but require to remember about this in your code.
In sbt changing 'working directory' via baseDirectory setting for test changes baseDirectory which is not base dir in my understangind and it is not equal new java.io.File(".").getAbsolutePath.
I'm not sure what the above statement means, but with sbt you need to fork to change your working directory during the run or test. This is documented in Enable forking and Change working directory.
If you fork, you can control everything, including the working directory.
http://www.scala-sbt.org/0.13.5/docs/Detailed-Topics/Forking.html
Example code:
fork in run := true
baseDirectory in run := file("/path/to/working/directory/")

Environment specific config in Play framework application

I've had a look around but it's not very clear to me how I can configure a set of environment specific variables for my Play framework application.
As an example, I would like to use an in memory database like h2 for local development but when I move to production or my pre-production environment I would like to be connecting to a postgres database.
How do I configure my app so that it will use the variables relevant to the environment it is being deployed to? This is a Scala Play app.
One option (as documented in the excellent play docs), is to specify conf files during app startup.
Using -Dconfig.resource will search for an alternative configuration file in the application classpath (you usually provide these alternative configuration files into your application conf/ directory before packaging). Play will look into conf/ so you don’t have to add conf/.
$ /path/to/bin/<project-name> -Dconfig.resource=prod.conf
Using -Dconfig.file you can specify an environment specific configuration file not packaged into the application artifacts:
$ start -Dconfig.file=/opt/conf/prod.conf
Using -Dconfig.url you can also specify a configuration file to be loaded from any URL:
$ start -Dconfig.url=http://conf.mycompany.com/conf/prod.conf
Note that you can always reference the original configuration file in a new prod.conf file using the include directive, such as:
include "application.conf"
key.to.override=blah
You can have Puppet or some similar tools to generate the needed parameters in environment.conf and place in a dedicated directory.
Then in application.conf, at the end of the file, have this:
include "file:///[your directory...]/environment.conf"
to override any testing or local values (e.g.DB parameteres) listed above
You can use different configuration files by overriding onLoadConfig method of the Global object like:
object Global extends GlobalSettings {
override def onLoadConfig(config: Configuration, path: File, classloader: ClassLoader, mode: Mode.Mode): Configuration = {
val fileName = s"application.${mode.toString.toLowerCase}.conf"
config ++ Configuration(ConfigFactory.load(fileName))
}
}
This way you have 'application.test.conf' for test mode and 'application.dev.conf' for develop mode whereas you can use another config file in production via '-Dconfig.file' parameter.

Configuration centralization for Play2 Scala; or how to stop hardcoding variables

At the moment, I'm hardcoding several variables like resource names and ports. I would like to move them out of my code.
What are recommended means of implementing a central configuration outside the actual code? Like a file maybe. So that, while the production and development are using same git repository, the configurations would be seperate. I am using Play 2 Framework on Scala.
I would suggest using the Typesafe Config library. It loads and parses files that can be a mix of .properties style, JSON, or extended JSON (called HOCON - "Human-Optimized Config Object Notation"), and is the configuration style used by Play 2 itself (and Akka, Spray, and a quickly growing list of other libraries).
In Play's standard application.conf file you can include files like so:
include "file:///..."
In this file you could override what properties you need to.
Additionally, (as documented in the excellent play docs), one can specify conf files during app startup like so:
Using -Dconfig.file
You can also specify another local configuration file not packaged into the application artifacts:
$ start -Dconfig.file=/opt/conf/prod.conf
Using -Dconfig.url
You can also specify a configuration file to be loaded from any URL:
$ start -Dconfig.url=http://conf.mycompany.com/conf/prod.conf
Note that you can always reference the original configuration file in a new prod.conf file using the include directive, such as:
include "application.conf"
key.to.override=blah
Configuration is likely a mean of taste, but Typesafe Config is one of the common libraries to use in scala/play ecosystem (e.g. it is used in akka).