Friday, 22 May 2015

Reloadable Configuration Files by observing any change


Some time there is need to reload config files when you change it, without restarting server. For this there is not so good example you can find on internet, So following code will help you to achieve this. This API developed using multi threading and Observable Design Pattern. First Create those class which will affected when a configuration file is change.

Two Observer class that will change as the config file change CronChangeObserver

 package com.bharat.observers;  
 import java.util.Observable;  
 import java.util.Observer;  
 public class CronChangeObserver implements Observer {  
      public void update(Observable o, Object arg) {  
           System.out.println("Cron reschedule started....since renewal property file changed");  
           //TODO call change method from here  
           System.out.println("Cron rescheduled successfully....since renewal property file changed");  
      }  
 }  
RenewalPropertyChangeObserver
 package com.bharat.observers;  
 import java.util.Observable;  
 import java.util.Observer;  
 public class RenewalPropertyChangeObserver implements Observer {  
      public void update(Observable o, Object arg) {  
           System.out.println("RenewalPropertyChangeObserver change started....since renewal property file changed");  
           //TODO call change method from here  
           System.out.println("RenewalPropertyChangeObserver change conpleted....since renewal property file changed");  
      }  
 }  

Now write a Observer that will notify all observables. PropertyChangeObservable
 package com.bharat.observable;  
 import java.text.SimpleDateFormat;  
 import java.util.Date;  
 import java.util.Locale;  
 import java.util.Observable;  
 
 public class PropertyChangeObservable extends Observable{  
      public void notifyObservers(Object arg)  
   {  
     setChanged();  
     super.notifyObservers(arg);  
   }  
   public void notifyObservers()  
   {  
     setChanged();  
     super.notifyObservers(null);  
   }  
Now a Watch Service of nio package and ChangeListener that catch changes in file. Just Instantiate it by passing Observer and File path that we have to watch, for any changes.
 package com.bharat.customer.services;  
 import java.io.IOException;  
 import java.nio.file.FileSystems;  
 import java.nio.file.Path;  
 import java.nio.file.Paths;  
 import java.nio.file.StandardWatchEventKinds;  
 import java.nio.file.WatchEvent;  
 import java.nio.file.WatchKey;  
 import java.nio.file.WatchService;  
 import java.util.Observable;  
 public class ConfigurationChangeListner implements Runnable{  
       private String configFileName = null;  
        private String fullFilePath = null;  
        private Observable observable=null;  
        public ConfigurationChangeListner(final String filePath, Observable observable) {  
          this.fullFilePath = filePath;  
          this.observable=observable;  
        }  
        public void run() {  
          try {  
               watchFile(this.fullFilePath);  
          } catch (IOException e) {  
            e.printStackTrace();  
          }  
        }  
        private void watchFile(final String file) throws IOException {  
          final int lastIndex = file.lastIndexOf("/");  
          String dirPath = file.substring(0, lastIndex + 1);  
          String fileName = file.substring(lastIndex + 1, file.length());  
          this.configFileName = fileName;           
          startWatchService(dirPath, fileName);  
        }  
        private void startWatchService(String dirPath, String file) throws IOException {  
          final WatchService watchService = FileSystems.getDefault()  
              .newWatchService();  
          Path path = Paths.get(dirPath);  
          path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);          
          WatchKey key = null;  
          while (true) {  
            try {  
              key = watchService.take();  
              for (WatchEvent< ?> event : key.pollEvents()) {  
                if (event.context().toString().equals(configFileName)) {  
                  configurationChanged(dirPath + file);  
                }  
              }  
              boolean reset = key.reset();  
              if (!reset) {  
                System.out.println("unable to reset watch key..........");  
                break;  
              }  
            } catch (Exception e) {  
              e.printStackTrace();  
            }  
          }  
          Runtime.getRuntime().addShutdownHook(new Thread() {  
            public void run() {  
              try {  
                watchService.close();  
              } catch (IOException e) {  
                e.printStackTrace();  
              }  
            }  
          });  
        }  
        public void configurationChanged(final String file) {  
          System.out.println("Configuration Changed Notifing all observers..................");  
          observable.notifyObservers();           
        }  
 }  
A threading program that will cause to run all to observers and hat start all functionality without restart
 package com.bharat.common;  
 import java.io.File;  
 import java.net.URISyntaxException;  
 import java.text.SimpleDateFormat;  
 import java.util.Date;  
 import java.util.Locale;  
 import java.util.Observable;  
 import org.springframework.context.ApplicationContext;  
 import org.springframework.context.support.ClassPathXmlApplicationContext;  
 import com.bharat.customer.services.ConfigurationChangeListner;  
 import com.bharat.observable.PropertyChangeObservable;  
 import com.bharat.observers.CronChangeObserver;  
 import com.bharat.observers.RenewalPropertyChangeObserver;  
 public class LoadChangeResource {  
      public static void main(String args[]){  
           ApplicationContext context = new ClassPathXmlApplicationContext(  
                     new String[] { "locale.xml", "Spring-Customer.xml" });  
           File f1 =null;  
           try {  
                f1 = new File(LoadChangeResource.class.getResource("/locale/customer/messages_en_US.properties").toURI());  
           } catch (URISyntaxException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
           }  
           RenewalPropertyChangeObserver renewalObs = new RenewalPropertyChangeObserver();  
           CronChangeObserver cronObs = new CronChangeObserver();  
           PropertyChangeObservable observable = new PropertyChangeObservable();  
           observable.addObserver(renewalObs);  
           observable.addObserver(cronObs);  
           String filePath=f1.getPath();       
         propertyChange(filePath,observable);  
      }  
      private static boolean propertyChange(String filePath, Observable observable) {  
           ConfigurationChangeListner listner = new ConfigurationChangeListner(filePath,observable);  
     try {  
       new Thread(listner).start();  
       while (true) {  
         Thread.sleep(2000l);          
       }  
     } catch (Exception e) {  
       e.printStackTrace();  
     }  
     return false;  
   }  
          
      public static String getCurrentTimeStamp() {  
           SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");//dd/MM/yyyy  
        Date now = new Date();  
        String strDate = sdf.format(now);  
        return strDate;  
      }  
 }  
Run this and enjoy.......