play 2.4.x current application environment - java

Is there any function to return the current working environment of a Play framework application ?
I tried the following but it doesn't seem to be working correctly;
String environment = play.api.Play.Mode
NOTE: I don't want to use isDev() isProd() stuff, I want to be able to create custom environments

PlayFramework 2.x supports only 3 modes: Prod, Dev and Test. First is used for production. Second provides more development additions like hotloading just editet classes. The last one is like the second one but with test libraries.
Play 1.x had also ID, which was able for using as different environment. For instance staging or instance of distributed server.
Play 2.x sadly doesn't support ID's anymore. But You can achieve the same effects manually.
Suppose you want to run your application in 'staging' mode.
First you need put configuration file along with basic configuration file, but named as application.staging.conf.
Second step is add to Global.scala code responsible for managing configuration files, something like this:
import java.io.File
import play.api._
import com.typesafe.config.ConfigFactory
object Global extends GlobalSettings {
override def onLoadConfig(config: Configuration, path: File, classloader: ClassLoader, mode: Mode.Mode): Configuration = {
val env = System.getProperty("environment")
val envConfig = config ++ Configuration(ConfigFactory.load(s"application.${environment}.conf"))
super.onLoadConfig(environmentSpecificConfig, path, classloader, mode)
}
}
As you see it reads environment value and look at specific configuration file.
The last step is telling play framework which mode it should use. The best way is by starting command:
activator run -Denvironment=staging
Should works.

In Java it is play.Application.isDev() and isProd() or isTest()
https://playframework.com/documentation/2.2.x/api/java/index.html

Related

How to use environment variables on a Spring Boot and Gradle application?

I explain my problem;
I have a web app developed using Vue.js and Spring Boot, this application working a PDF sheet and saves the file that is generated by Java, I use two lines of code to separate my development part from the production part (I leave you the 2 lines of code like this you understand the concept well)
FileReader leggoFile = new FileReader(System.getProperty("user.dir") + "/temp/webapps/foolder/foolder/file.pdf");
// FileReader leggoFile = new FileReader(System.getProperty("catalina.base") + "/temp/webapps/foolder/foolder/file.pdf");
This whole application is built using the "bootWar gradle plugin" which returns me a .war which I will then upload to a Tomcat server;
My goal is this:
I would like to set a single environment variable so that if I want to build the project I don't have to comment/uncomment that line for example:
FileReader leggoFile = new FileReader({{variableEnvironment}} + "/temp/webapps/foolder/foolder/file.pdf")
my question is this:
How dp Gradle and Spring Boot handle environments? Is there a way to separate environments? Is this possible or should I start thinking differently?
I tried to search on something but unfortunately I was tied to the problem that I don't understand how the .war file is generated through the BootWar Gradle plugin, also searching on the internet I understood that environment Gradle and environment Spring are two separate things but in general even if I know the line of code is wrong in the beginning my question is always the same:
How are environment variables handled in Spring and Gradle?
With Spring Boot, you can add properties to your application by adding an file named application.yaml to your resources folder (src/resources/). In addition you can add properties through application-{profile}.yaml to add properties only for given Spring profiles. For instance application-test.yaml would only be read if "test" is an active profile. When booting up the application, Spring will first read application.yaml, then any profile-specific YAML-files, such that any overlapping properties are replaced.
There are several approaches to injecting the property. A simple solution is to add a field to your component annotated with #Value("${PATH}) and replace PATH with the property's path in the YAML.

Can I change a database depending on the branch I am on (specified in Dockerfile)?

I would like to have my:
spring.datasource.url = jdbc:mysql://666.666.666.666/prod_very_wow
Change into:
spring.datasource.url = jdbc:mysql://666.666.666.666/dev_very_wow
According to the branch I am currently on. I think I should also have it specified within the Dockerfile - I should have a property added next to docker's RUN which should determine which data source ought to be activated.
Namely, I would like my app to be connected to prod_very_wow when I am on master branch and dev_very_wow everytime I am checking out to dev or creating a new feature branch and have it all determined by a property added to RUN mvn package within the Dockerfile.
I apologise if the question makes no sense, but, frankly - I am a little bit clueless how to ask this question and so I have troubles googling for answers.
I just found a couple of leads about "environmental variables", but I can't find any connection between the datasource connected to and the branch I am currently on.
The best way to handle different configuration based on environment is to have decoupled your code from your configuration that is one of the twelve-factor apps principles. In this case you should have an external config server, like spring cloud config server, that will host the configurations files for the different environments and the application will ask this config server for the proper config file depending on the environment where it is deployed.
However, if you don't want to follow this approach you can create the different configuration files in the application and use an environment variable that tells spring which file to use. For example, in your case you can have an application-local.yaml and application-prod.yaml, and then if you want to specify it in the dockerfile in the mvn package command, you can use:
RUN mvn -Dspring.profiles.activ=local package
RUN mvn -Dspring.profiles.activ=prod package

SpringBoot library project does not see main app properties

I have a setup like this:
Main SpringBoot project with application-default.properties which on our deployment server are partially overwritten by a deployment specific properties.
Shared SpringBoot library project which has its own properties.
And when I run my main project with the library project attached (via gradle sourceControl gitRepository) I can see that the properties in the library project are empty.
How can I make the library project use the properties passed down from the main application ?
If you want to merge properties, please consider this official page.
Option 1 - default properties in library
As I found previously (probably, it is fixed), if you have jar1 and jar2 (sorted alphabetically) and both of them have application.properties file, only first will be used. They aren't merged. So please be carefully there.
However you can use #PropertySource in your library, e.g. put default properties there into the custom file name (for example - defaults-for-jar2.properties or something like this, to avoid automatic loading by Spring).
In this case:
Property load logic outside of your library will be the same with current.
Your library will load file from #PropertySource and next they will be overridden (if you have this) by your application.
Option 2 - configuration properties
If you use Kotlin and Spring, you can use ConfigurationProperties. And you can define the default values there. Moreover, IntelliJ Idea will highlight the default and possible values (according to the type, because you can use not only String, but any custom enum class, Duration class, etc.).
Just from that link:
#ConstructorBinding
#ConfigurationProperties("blog")
data class BlogProperties(var title: String, val banner: Banner) {
data class Banner(val title: String? = null, val content: String)
}
#SpringBootApplication
#EnableConfigurationProperties(BlogProperties::class)
class BlogApplication {
// ...
}
Please note:
You should mention your settings data class in the library configuration.
You should configure kapt properly to have Intelli Sence in IDEs.

Setting environment for property location

I am configuring my spring application using property file. But I have to make a switch between development and production property file. Current I have this code snippet
#Configuration
#PropertySource(value = "classpath:config/simulator.properties", ignoreResourceNotFound = false)
public class AppConfiguration
But I would like something with value = "classpath:${env:local}/simulator.properties"
which means if I not set the environment variable env than it must point to local/simulator.properties else if environment env variable points to production the location must be production/simulator.properties.
So, the local is the fallback environment.
Is there any way to achieve this. I do not want to use profiles, it must be controlled by an environment variable
I do not want to set a -D option for profiles
Thanks
Johan
You can use multiple #PropertySource annotations, if the first file and the second file are found, and the keys in both the file matches then the later one will be taken. Please have a look at here
#PropertySource(value="classpath:local/simulator.properties",ignoreResourceNotFound=true)
#PropertySource(value="classpath:${env.production}/simulator.properties",ignoreResourceNotFound=true)
Spring automatically look at from system root path if we have windows then c:/ will be automatically understood by spring and if we have Linux machine then / will be root.
So here we don't need to set classpath or -D tags.
Actually in my Tests (Unit Test 4) I used annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:com/myTest/MyTestApplicationContext.xml"})
This allows you to have a separate Application context for each test and separate one for development environment. Then of course in each of your Application contexts you can configure properties to be read from different place. Works great for me

Need in understanding classpath in resource location and variable value set

Although I have been working in java for a while, there are many small things I have been ignoring, which at times have become bottleneck in productivity. I have difficulty in understanding this:
This is one of the bean.xml which gets placed in the final .war file (in a web application, built with spring framework).
<context:property-placeholder
location="classpath:/${deploy.env}/com.example.config/db.properties"
ignore-resource-not-found="false" />
I have following doubts:
1) At the time of building the code, i did like this for passing value of deploy.env
mvn clean install -Ddeploy.env=local
I ran the mvn in debug mode and could see this set to local. Now, the thing is, in the .war that gets generated, it is still ${deploy.env} (see above snippet). Doesn't this get replaced in the final .war? If not, then how do we pass the value which we intend to set?
2) what does "classpath:/${deploy.env}/com.example.config/db.properties" mean? Who sets the value of classpath? Are classpath capable of providing the location of resource files as well?
Assuming deploy.set --> local, so would this get translated to:
classpath:"/local/com.example.config/db.properties"
So does this mean db.properties would be present at: /local/com.example.config/db.properties
Any inputs to understand this would be of great help.
deploy.env is either environment variable or system property available to the JVM at run time.
The classpath:/${deploy.env}/com.example.config/db.properties will be resolved at run when your war is running in the container.
Set deploy.env=whatever in the shell from where you starting the tomcat or set in the environment of the user which starts the tomcat.
mvn clean install -Ddeploy.env=local here the deploy.env system property is available at build time. This will not replace the value of your spring config.
classpath is where all your classes and libraries bundled in the war are available along with the tomcat libraries. The spring property configurer will look for the db.properties file in the classpath at location e.g. /local/com.example.config
Spring documentation to learn more
Some explanation on my blog post
As stated in the Oracle Web site: The CLASSPATH variable is one way to tell applications, including the JDK tools, where to look for user classes.
That classpath: is referring to that location in particular, whatever it is, so it will start looking for those resources defined by Spring from that location and on, until it finds the first match.
Also, if you have that as a property in Maven, the value can be replaced with the right plug-in and configuration; not quite useful when you want a build that can be used with many values within those .properties files for different environments.
You can use other prefixes as file:, http:, etcetera. But you are just wondering about classpath:.

Categories