Core Java

Dead simple configuration

Whole frameworks have been written with the purpose of handling the configuration of your application. I prefer a simpler way.

If by configuration we mean “everything that is likely to vary between deploys“, it follows that we should try and keep configuration simple. In Java, the simplest option is the humble properties file. The downside of a properties file is that you have to restart your application when you want it to pick up changes. Or do you?

Here’s a simple method I’ve used on several projects:

 
 

public class MyAppConfig extends AppConfiguration {

    private static MyAppConfig instance = new MyAppConfig();

    public static MyAppConfig instance() {
        return instance;
    }

    private MyAppConfig() {
        this("myapp.properties");
    }

    public String getServiceUrl() {
        return getRequiredProperty("service.url");
    }

    public boolean getShouldStartSlow() {
        return getFlag("start-slow", false);
    }
    
    public int getHttpPort(int defaultPort) {
        return getIntProperty("myapp.http.port", defaultPort);
    }

}

The AppConfiguration class looks like this:

public abstract class AppConfiguration {

    private static Logger log = LoggerFactory.getLogger(AppConfiguration.class);

    private long nextCheckTime = 0;
    private long lastLoadTime = 0;
    private Properties properties = new Properties();
    private final File configFile;

    protected AppConfiguration(String filename) {
        this.configFile = new File(filename);
    }

    public String getProperty(String propertyName, String defaultValue) {
        String result = getProperty(propertyName);
        if (result == null) {
            log.trace("Missing property {} in {}", propertyName, properties.keySet());
            return defaultValue;
        }
        return result;
    }

    public String getRequiredProperty(String propertyName) {
        String result = getProperty(propertyName);
        if (result == null) {
            throw new RuntimeException("Missing property " + propertyName);
        }
        return result;
    }

    private String getProperty(String propertyName) {
        if (System.getProperty(propertyName) != null) {
            log.trace("Reading {} from system properties", propertyName);
            return System.getProperty(propertyName);
        }
        if (System.getenv(propertyName.replace('.', '_')) != null) {
            log.trace("Reading {} from environment", propertyName);
            return System.getenv(propertyName.replace('.', '_'));
        }

        ensureConfigurationIsFresh();
        return properties.getProperty(propertyName);
    }

    private synchronized void ensureConfigurationIsFresh() {
        if (System.currentTimeMillis() < nextCheckTime) return;
        nextCheckTime = System.currentTimeMillis() + 10000;
        log.trace("Rechecking {}", configFile);

        if (!configFile.exists()) {
            log.error("Missing configuration file {}", configFile);
        }

        if (lastLoadTime >= configFile.lastModified()) return;
        lastLoadTime = configFile.lastModified();
        log.debug("Reloading {}", configFile);

        try (FileInputStream inputStream = new FileInputStream(configFile)) {
            properties.clear();
            properties.load(inputStream);
        } catch (IOException e) {
            throw new RuntimeException("Failed to load " + configFile, e);
        }
    }
}

This reads the configuration file in an efficient way and updates the settings as needed. It supports environment variables and system properties as defaults. And it even gives a pretty good log of what’s going on.

  • For the full source code and a magic DataSource which updates automatically, see this gist: https://gist.github.com/jhannes/b8b143e0e5b287d73038

Enjoy!

Reference: Dead simple configuration from our JCG partner Johannes Brodwall at the Thinking Inside a Bigger Box blog.

Johannes Brodwall

Johannes works as a programmer, software architect and provocateur for Sopra Steria Norway. He loves writing code in Java, C# and JavaScript and making people think.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ricardo
Ricardo
10 years ago

You really should check the library
http://lviggiano.github.io/owner/
It is small and great for this kind of configuration

Back to top button