I’ve got a JavaEE environment (in my particular case it’s a Glassfish Web Profile) and I want a container independent way of configuring my application with the following features:
My wish would be that there are as few preconditions as possible (the only one now is a JNDI datasource) to deploy and run my application (Set up JNDI datasource, deploy WAR file, have an optional .properties file in some configuration folder and - done).
This leads me to my first question: Is this a common/good/useful setup or is it unnecessarily complicated and/or very exotic?
The default configuration would be in a properties file:
src/main/resources/config/default.properties
An application scoped bean reads this properties on initialization as described here:
@Named
@ApplicationScoped
public class Configuration implements Serializable {
...
@PostConstruct
public void initConfiguration() {
loadDefaultConfiguration();
}
private void loadDefaultConfiguration() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try (InputStream input = classLoader.getResourceAsStream("/config/default.properties")) {
properties.load(input);
} catch(IOException ex) {
LOGGER.error(...);
}
}
}
These settings will be stored in a database table with key and value columns. They'll be always accessed via an EntityManager, hoping the caching of the JPA implementation will be clever :). The advantage here is, that these settings can easily be changed while the application is running.
@Named
@ApplicationScoped
public class Configuration implements Serializable {
...
public T getProperty(final PropertyKeyEnum key, final Class<T> type) {
if (key.getSource() == PropertySourceEnum.DATABASE) {
return configurationDao.getByKey(key.getKey(), type);
}
...
}
}
Finally, here is my main problem:
How do I access an external properties file in a container independet way? The user shall be able to just place a myAppName.properties
file into the default configuration folder of the container and the application shall be able to find and load this file (at least on application startup).
I've found a place in the admin area of Glassfish where you can specify some system properties which are easily accessable:
System.getProperty("myApp.propertyName");
This could be used to store the path to the external .properties file, but I'm not sure if this is a clean way because
Configuration management (CM) is a governance and systems engineering process used to track and control IT resources and services across an enterprise.
Configuration Management is the process of maintaining systems, such as computer hardware and software, in a desired state. Configuration Management (CM) is also a method of ensuring that systems perform in a manner consistent with expectations over time.
Configuration management can be used to maintain OS configuration files. Example systems include Ansible, Bcfg2, CFEngine, Chef, Nix, Otter, Puppet, Quattor, SaltStack, Terraform, Pulumi and Vagrant. Many of these systems utilize Infrastructure as Code to define and maintain configuration.
A configuration file, often shortened to config file, defines the parameters, options, settings and preferences applied to operating systems (OSes), infrastructure devices and applications in an IT context. Software and hardware devices can be profoundly complex, supporting myriad options and parameters.
After talking with my colleagues and some research I've implemented the following for the host specific (external) configuration.
As I need a working directory for my application anyway, I decided to use this working directory also as the location for my external configuration. Therefore I either use an environment variable (e.g. MYAPP_HOME
) or, if the variable is not set, the user's home folder (e.g. <user.home>/.myapp
):
private Path discoverRootDirectory() {
String myAppHome = System.getenv("MYAPP_HOME");
if (myAppHome == null) {
return Paths.get(System.getProperty("user.home"), ".myapp");
} else {
return Paths.get(myAppHome);
}
}
The properties file will then be loaded as usual:
private void loadConfiguration() {
properties = new Properties();
// ...
try (InputStream inputStream = Files.newInputStream(discoverRootDirectory())) {
properties.load(inputStream);
} catch (FileAccessException | IOException ex) {
// ...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With