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
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) {
// ...
}
}