I recently wrote an example application to create invoices. In it I used Google’s OAuth2 authentication, which naturally requires application specific API keys and secrets from Google that I cannot share publicly in the demo sources. As OAuth2 was just one thing I wanted to demonstrate, I wanted the application to seamlessly boot into “development mode”, if the user hasn’t defined his secret values. I also used the application in a hobby project and didn’t want to have different git branches for the example and the “production” version.
Many Java developers are still using the good old java.util.Properties class. It is pretty handy, but if your properties are defined in a properties file in your war file, why wouldn’t you define the values directly as Java constants? And if you put the properties file to a fixed location outside your war file, your application will become less portable.
If you are basing your application on a Java EE stack or using a manually set up CDI container, DeltaSpike core has a powerful alternative to basic Property file usage that will help in the scenarios described above. It allows you to have several property files, from different libraries, and also other means to override the property values after the binaries have been built.
Using basic properties with DeltaSpike is even simpler than with Properties files. You can just fetch the properties with a static helper method:
String dbUserName = ConfigResolver.getPropertyValue("databaseconfig.username");
For more advantaged usage, there are lots of goodies, like typed API, default values (as second parameter) and project stage specific parameters. But probably the coolest method to use properties is to just inject it into your managed bean. This is what I did in my example:
@Inject @ConfigProperty(name = "jpa-invoicer.gpluskey") private String gpluskey;
Check out the DeltaSpike documentation to see all usage possibilities.
Defining and “overriding” the property values
The basic place for property values is META-INF/apache-deltaspike.properties file. The handy thing in those files is that you can have one per each library. So if your web app contains other libraries, they can have their default property values defined in those projects and you can then optionally override them in the “.war” project. Naturally you might want to use build time filtering (e.g. with Maven) for the properties files.
The properties files are by no means the one and only way you can define your properties. The property value resolution can be easily customized to anything you’d like, but the default sources are already pretty flexible. The values defined in the properties files are kind of the weakest ones and are overridden by JNDI values (with base name “java:comp/env/deltaspike/”), environment values and system properties, so that system properties have the most weight.
This opens up many different mechanisms to configure settings suitable for e.g. different development needs, testing and production. In the case of my example application, if a user wants to enable the OAuth2 authentication (and define the API key and secret), he can do it e.g. in the following different methods:
- Define the key and secret value right into the java file (and remove annotations from the fields).
- Modify META-INF/apache-deltaspike.properties to directly contain the key and secret values.
- Define the properties in pom.xml or preferably in a Maven profile (e.g. in ~/.m2/settings.xml). The build is set to filter the apache-deltaspike.properties files so that Maven properties are placed into it.
- Give them as command line parameters when launching the server (-Djpa-invoicer.gpluskey=123456)
- Define them as project wide properties in IDE (passed as environment variables for launched Java processes)
- Define them as environment variables on the system running your server, either in local development workstation or in a real deployment server.
Options 1 & 2 are really “handy” for developers. The issue with these approaches is that the secret keys might be accidentally committed to the sources repository. In option 3 the properties are defined at build time. This, especially if you use developer/CI-server specific profiles, is already a much better solution.
The problem in solutions 1-3 is that you might want to use the same war file, but different property values, in “staging” and “production” environments. In method 4 we override the value with a command line parameter. This may be a handy method for quick testing, but for production deployment and basic development cycle you’ll probably want to use more persistent methods. Like suggested in option 5, modern IDEs let you define project wide properties that will then be picked up by your Maven build and/or server launch.
The last option, and I’d say often the most handy one, is to define the properties as environment variables. With environment variables your configurations will be persistent as well. Then you could, in this case, decide at your development environment whether you want to enable OAuth or use development mode with an automatically logged in fake user. On your production machine you can just define the key and secret to your servers BASH profile and the OAuth2 won’t be accidentally disabled in production, even if a developer deploys a “hotfix version” built on his local development environment.
The fact that DeltaSpike will by default read properties also from environment variables makes it really handy in various cloud services. I used this mechanism recently when I built a Java library for Watson services. The library needs no configuration at all when deployed to cloud, as it reads the service authentication keys directly from the CloudFoundry environment variables (VCAP_SERVICES environment variable). Just wire the services together in Bluemix control panel and inject the desired service class to your Vaadin/Java code.