Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Commons Configuration2 ReloadingFileBasedConfiguration

I am trying to implement the Apache Configuration 2 in my codebase

import java.io.File;
import java.util.concurrent.TimeUnit;

import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration2.event.EventListener;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.reloading.PeriodicReloadingTrigger;

import org.apache.commons.configuration2.CompositeConfiguration;

public class Test {

    private static final long DELAY_MILLIS = 10 * 60 * 5;


    public static void main(String[] args) {
        // TODO Auto-generated method stub
        CompositeConfiguration compositeConfiguration = new CompositeConfiguration();
        PropertiesConfiguration props = null;
        try {
            props = initPropertiesConfiguration(new File("/tmp/DEV.properties"));
        } catch (ConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        compositeConfiguration.addConfiguration( props );
        compositeConfiguration.addEventListener(ConfigurationBuilderEvent.ANY,
                new EventListener<ConfigurationBuilderEvent>()
                {
                    @Override
                    public void onEvent(ConfigurationBuilderEvent event)
                    {
                        System.out.println("Event:" + event);

                    }
                });

        System.out.println(compositeConfiguration.getString("property1"));

        try {
            Thread.sleep(14*1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // Have a script which changes the value of property1 in DEV.properties
        System.out.println(compositeConfiguration.getString("property1"));
    }

    protected static PropertiesConfiguration initPropertiesConfiguration(File propsFile) throws ConfigurationException { 

        if(propsFile.exists()) {

            final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder =
                    new ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration>(PropertiesConfiguration.class)
                    .configure(new Parameters().fileBased()
                        .setFile(propsFile)
                        .setReloadingRefreshDelay(DELAY_MILLIS)
                        .setThrowExceptionOnMissing(false)
                        .setListDelimiterHandler(new DefaultListDelimiterHandler(';')));
            final PropertiesConfiguration propsConfiguration = builder.getConfiguration();
            PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(builder.getReloadingController(),
                    null, 1, TimeUnit.SECONDS);
                trigger.start();

            return propsConfiguration;
        } else {
            return new PropertiesConfiguration();
        }

    }
}

Here is a sample code that I using to check whether the Automatic Reloading works or not. However when the underlying property file is updated, the configuration doesn't reflect it.

like image 486
Avin Avatar asked Oct 19 '22 11:10

Avin


1 Answers

As per the documentation :

One important point to keep in mind when using this approach to reloading is that reloads are only functional if the builder is used as central component for accessing configuration data. The configuration instance obtained from the builder will not change automagically! So if an application fetches a configuration object from the builder at startup and then uses it throughout its life time, changes on the external configuration file become never visible. The correct approach is to keep a reference to the builder centrally and obtain the configuration from there every time configuration data is needed.

https://commons.apache.org/proper/commons-configuration/userguide/howto_reloading.html#Reloading_File-based_Configurations

This is different from what the old implementation was.

I was able to successfully execute your sample code by making 2 changes :

  1. make the builder available globally and access the configuration from the builder :

    System.out.println(builder.getConfiguration().getString("property1"));

  2. add the listener to the builder : `builder.addEventListener(ConfigurationBuilderEvent.ANY, new EventListener() {

        public void onEvent(ConfigurationBuilderEvent event) {
            System.out.println("Event:" + event);
        }
    });
    

Posting my sample program, where I was able to successfully demonstrate it

import java.io.File;
import java.util.concurrent.TimeUnit;

import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.event.EventListener;
import org.apache.commons.configuration2.reloading.PeriodicReloadingTrigger;

public class TestDynamicProps {
    public static void main(String[] args) throws Exception {

        Parameters params = new Parameters();
        ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder =
            new ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration>(PropertiesConfiguration.class)
            .configure(params.fileBased()
                .setFile(new File("src/main/resources/override.properties")));
        PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(builder.getReloadingController(),
            null, 1, TimeUnit.SECONDS);
        trigger.start();

        builder.addEventListener(ConfigurationBuilderEvent.ANY, new EventListener<ConfigurationBuilderEvent>() {

            public void onEvent(ConfigurationBuilderEvent event) {
                System.out.println("Event:" + event);
            }
        });

        while (true) {
            Thread.sleep(1000);
            System.out.println(builder.getConfiguration().getString("property1"));
        }

    }
}
like image 144
linkcrux Avatar answered Oct 30 '22 13:10

linkcrux