Scala SBT Project Application Configuration File - scala

I come from the C# .NET world and as I build my Scala project I noticed how many different ways there are to do things in the open source community. Anyways in .Net C# project we have the Web.config or the App.config file which is very useful to specify app keys that are used globally and it is also helpful for transformation for different environments and such.
What would be the equivalent for a Scala SBT project? Do you know a place to store your connection strings and other app settings?

There is no universal configuration file name. The basic way is to use Properties, see e.g. how to read properties file in scala, and call the file your-application-name.properties. But there is a popular library called simply Config which I'd recommend; as https://github.com/typesafehub/config#standard-behavior says, its standard names for config files are
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)
The idea is that libraries and frameworks should ship with a reference.conf in their jar. Applications should provide an application.conf , or if they want to create multiple configurations in a single JVM, they could use ConfigFactory.load("myapp") to load their own myapp.conf . (Applications can provide a reference.conf also if they want, but you may not find it necessary to separate it from application.conf .)
As #ashalynd's answer says, in order for any such library to see your configuration files, they should go into src/{main,test}/resources.

I think you are talking about application.conf. It can be found in /src/main/resources or in /src/test/resources (affecting main and test settings, respectively). If application.conf is not present in /src/test/resources, the main application.conf will be used for the tests.

Related

Where exactly does application.conf live in the project directory structure?

The Play website says it should be in "conf", but the Lagom default HelloeWorld example places it under the "resources" directory within /applicationProject/src/main". "conf/" does not even show up anywhere in the directory structure in Lagom. Can someone clarify?
According to default Play project layout
application.conf located at conf/application.conf. So if you will inject play.api.Configuration this will represent parsed and loaded config from that file.
On another hand I suppose, Lagom is library, which relies on default Maven project layout, which differs from default Play layout, in which src/main/resources is standard folder for resources like configuration, which is why in Lagom project example you see application.conf in another folder then in Play.
What you can do as an option: take play.api.Configuration.underlying and pass manually to Lagom code.
Or keep using standard Maven project layout for Play via special plugin introduced after version 2.6.8: https://www.playframework.com/documentation/2.6.x/Highlights26#PlayService-sbt-plugin-(experimental)
Hope this helps!

What is the correct way of using static assets in a Scala SBT project?

What is the best way of using static resources in an SBT based Scala project with a packaging plugin such as sbt-assembly or sbt-native-packager.
We know that by using TypeSafe-Config with sbt-native-packager's universal plugin, we can just put the configuration file in the resources directory under sources. However, what if I wanted my application to have other static sources such as JSON files containing mappings, and models?
I understand that I can just reference the resources directory and read from the file, but would that still work after packaging the application with plugins (assuming the universal or docker plugin in this case)?
If not, what is the correct way to achieve this?
You could use
unmanagedResourceDirectories += (baseDirectory in <project>).value / some / path
to add more directories that are later mapped into the jar as static resources.
Put it into the resources directory, but don't "reference the resources directory and read from the file": use ClassLoader.getResourceAsStream() (or getResources, depending on your requirements) instead. This is the same technique TypeSafe Config and innumerable other libraries use. For this it doesn't matter if you use sbt-native-packager or not.
This approach runs into problems if you need to make these resources available specifically as files (e.g. to feed them to an external process). In this case add them to mappings as shown here:
mappings in Universal in packageBin += file("README") -> "README"
(obviously replacing "README" with the file(s) you need).

Swapping out .properties files for different environments

I have a Play 2 application that uses some external Java libraries. Some of these (e.g. the Paypal merchant sdk) depend on having a properties file for configuration (e.g. sdk_config.properties) which I have put into the conf directory.
When deploying this application to a different environment using play dist is there a sensible way to swap out properties files for each environment? For the main configuration in application.conf this is straightforward e.g. start -Dconfig.resource=prod.conf, but I am not sure how to do something similar for the properties files.
The support for specifying config.resource (and a lot of other nice stuff) is built into the typesafe config lib that comes with play. Other third party libs that depend on properties files on the classpath may or may not accept something like that, so if you are lucky then there is a lib specific way to point it to a separate config file.
If they do not then the only option is to somehow provide a different file on the classpath for the different environments. This could basically be done in two ways:
A. To not ship the file with the artifact and instead provide it per environment and add that on the classpath when starting play.
B. To create different artifacts for the different configurations, this would require you to customize dist to create one artifact per distinct env.
I would go for A since it allows there to be one artifact that can be run anywhere, but it might add some annoyances to running the app in a dev env etc.

External configuration for Play 2 Framework

I have a custom configuration file for my database, and I want to externalize it when my Play project is packaged into a war.
I tried javaOptions in build.sbt with the -DConfig.file java command, but my file is not detected...
my line : javaOptions in run += "-Dconfig.file=conf/database.conf"
and my deployed war on a Tomcat server is :
/mywar/META-INF/MANIFEST.MF
/mywar/WEB-INF/lib/myplayproject.jar (with other dependencies)
I put my conf file in lib directory : /lib/conf/database.conf
Where am I doing wrong ?
(based on this link : http://www.scala-sbt.org/0.12.3/docs/Detailed-Topics/Forking.html)
If you deploy your war on Tomcat, I don't see how sbt is involved, which may explain why your option is ignored.
Play is not really meant to be deployed as a war. I think the easiest thing for you would be to manually load the config file in your code via the typesafe config library.
When deploying to a container you aren't in control of the JVM process so you can't specify command line options to set system properties.
Your easiest approach here is probably to just rename your config file to reference.conf or application.conf. Those two names are auto-loaded by the configuration library from the classpath.
You could also edit reference.conf or application.conf to add include "database.conf" if you want to keep a separate file.
Otherwise you could manually load a config file, e.g. with ConfigFactory.parseResource to search the classpath.
In addition to including classpath resources you can include files and urls out of the box. Use the include url("http://example.com") or include file("foo.conf") syntax. By hand (in code) ConfigFactory can of course also parse urls and files.
If that isn't flexible enough, it's also possible to customize includes in two ways.
One is to create a custom ConfigIncluder http://typesafehub.github.io/config/latest/api/com/typesafe/config/ConfigIncluder.html
The other is to create a custom URL protocol in the usual Java way, see Creating custom URI scheme using URI class and http://www.cooljeff.co.uk/2009/12/12/custom-url-protocols-and-multiple-classloaders/ for example. Then use include url("myproto:foobar")

Can I read property file with jetty in development?

I am working on a lift project as a sub-project in a gigantic mvn project. I put the property files into:
src/main/resources/props/staging.props
src/main/resources/props/production.props
in the sub-project folder.
Then I run jetty with:
mvn jetty:run -Drun.mode=staging
I printed out the settings from net.liftweb.util.Props using:
println("file_name:" + Props.fileName)
println("mode_name:" + Props.modeName)
The output:
file_name:lift.props
mode_name:staging
The mode name is correct. However, the file name is totally wrong. net.liftweb.util.Props is still using the file name that had been hardcoded in the source. It seemed never reached my property file.
Am I missing something? Or it cannot work with jetty?
While duffymo is right and you can just use the underlying servlet facilities for getting resources, I would still use Lift's Properties abstraction. It already does the work for differentiating different run modes. It also allows you to have different properties per-user and/or per-machine, which can be useful, depending on your development team.
The default properties for a given mode should be put in /props/modeName.default.props, so your files should be renamed to:
src/main/resources/props/staging.default.props
src/main/resources/props/production.default.props
I would put the .properties file in your /WEB-INF/classes and use the servlet context's getResourceAsStream() to read it in.