Tuesday, January 14, 2014

Dynamic switching between the properties files using ReloadableResourceBundleMessageSource


Dynamic switching between the properties file path using ReloadableResourceBundleMessageSource
ReloadableResourceBundleMessageSource is a class which is provided by spring framework to reloading the properties, which are specified.
In this example shown dynamic switching between base_vx_en_US.properties   and base_vx_v1_en_US.properties  two files


The ReloadableResourceBundleMessageSource bean looks like as shown below in XML file
(Configured only base_vx_v1_en_US.properties )



















<bean id="messageSource"                   class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> 
                                      <property name="basenames">                                                                                  
                                                   <list>
                                                            <value>classpath:base_vx</value>
                                                    </list>              
                                      </property>
  </bean>

 Which reloads the properties file (base_vx.properties) based on cache seconds specified.

 we can read properties using below code snippet

   
  @Controller
    public class HelloWorldController {
               
                                @Resource(name = "messageSource")
                                private CustomReloadableResourceBundleMessageSource messageSource;
                               
                                @RequestMapping("/hello")
                                public ModelAndView helloWorld() {
                                               
                                                String[] params = {""};
                                                String message = messageSource.getMessage("example.welcome", params,   
                                                                                                Locale.US);
                                                return  new ModelAndView("hello", "message", message);
                                }

    }
               
 But, if we want to switch between two files dynamically like in above code am reading base_vx_en_US.properties,but if i want to read base-v1.properties instead of base_vx_v1_en_US.properties  by switching dynamically , What should I do?

 Here is the solution:

 Steps:
   1) A Class which extends ReloadableResourceBundleMessageSource
   2) Override necessary methods in ReloadableResourceBundleMessageSource.
   3) need a flag to switch between two files (in this example “ propertiesSwitchFlag”).
 
package com.sape.vox.config;


import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.springframework.context.support.ReloadableResourceBundleMessageSource;

public class CustomReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource{
               
                private String[] basenames = new String[0];
               
                private long cacheMilliSec;
               
                private long refreshTimeStamp;
               
                public long getRefreshTimeStamp() {
                                return refreshTimeStamp;
                }

               
               
               
                public enum BASEURLS {
                                BASE_OLD_PATH("classpath:base_vx"),
                                BASE_NEW_PATH("classpath:base_vx_v1");
        private String value;

        private BASEURLS(String value) {
                this.value = value;
        }
       
        @Override
        public String toString() {
            return value;
        }
                };  

                @Override
                public void setCacheSeconds(int cacheSeconds) {
                                this.cacheMilliSec = cacheSeconds *1000;
                                this.refreshTimeStamp =  System.currentTimeMillis();
                               
                                super.setCacheSeconds(cacheSeconds);
                }
               
                /**
                 * Overridden method to set the basenames
                 */
                @Override
                public void setBasenames(String[] basenames) {
                                                if (basenames != null) {
                                                                this.basenames = new String[basenames.length];
                                                                for (int i = 0; i < basenames.length; i++) {
                                                                                String basename = basenames[i];
                                                                                this.basenames[i] = basename.trim();
                                                                }
                                                }
                                                else {
                                                                this.basenames = new String[0];
                                                }
                                               
                                                super.setBasenames(basenames);
                }
               
                /**
                 * Replace the path of the property file from set of basenames
                 * @param oldPath
                 * @param newPath
                 */
                private void replaceFilePath(String oldPath,String newPath){
                                String[] existingBasenames = this.basenames;
                               
                                List<String> temp = new ArrayList<String>(Arrays.asList(existingBasenames));
                               
                                int oldPathIndex = temp.indexOf(oldPath);
                               
                                if(oldPathIndex != -1){
                                                temp.remove(oldPathIndex);
                                                temp.add(newPath);
                                }
                               
                                existingBasenames = (String[]) temp.toArray(new String[temp.size()]);
                                setBasenames(existingBasenames);
                }
               
               
                @Override
                protected String resolveCodeWithoutArguments(String code, Locale locale) {
                                refreshBaseNames();
                                return super.resolveCodeWithoutArguments(code, locale);
                }
               
                @Override
                protected MessageFormat resolveCode(String code, Locale locale) {
                                refreshBaseNames();
                                return super.resolveCode(code, locale);
                }
               
                /**
                 * Checks for the cache whether it has expired or not
                 * @return
                 */
                private boolean isCacheExpired(){
                                return (System.currentTimeMillis() -this.refreshTimeStamp > this.cacheMilliSec);
                }
               
                /**
                 * Checks for the flag and calls replaceFilePath to replace propert file from set of
                 * basenames
                 */
                private void refreshBaseNames(){
                                if(isCacheExpired()){
                                                Map<String,String> pathMap = new HashMap<String,String>();
                                               
                                                // This flag you can set dynamically by getting it from database
                                                boolean propertiesSwitchFlag = true;
                                               
                                                if(propertiesSwitchFlag == true){
                                                                pathMap.put(BASEURLS.BASE_OLD_PATH.toString(), BASEURLS.BASE_NEW_PATH.toString());
                                                }else{
                                                                pathMap.put(BASEURLS.BASE_NEW_PATH.toString(),BASEURLS.BASE_OLD_PATH.toString());
                                                }
                                               
                                                for (Map.Entry<String, String> entry : pathMap.entrySet()) {
                                                    String key = entry.getKey();
                                                    String value = entry.getValue();
                                                    replaceFilePath(key,value);
                                                }
                                               
                                                this.refreshTimeStamp = System.currentTimeMillis();
                                }
                }
               
}




No comments:

Post a Comment