Monday, 20 January 2014

Spring AbstractRoutingDataSource for Multiple Schemas/DB

Spring AbstractRoutingDataSource for Multiple Schemas/DB helps to change the database dynamically.
For example, I can explain the situation as  follows.
Suppose you have an application which supports multiple languages and you want to connect to different databases on language selection. Then you can go with this approach and redirect the user based on the language selected.
The steps are below.

JSP:



  • Create a select box populated with all the language, and on change call a struts action with the help of ajax.


<s:select headerKey="-1" headerValue="Select Language"
list="#{'en':'English','hi':'Hindi','ka':'Kannada','ta':'Tamil','te':'Telugu'}"
name="language" onchange="changeLanguage(this) "/>

AJAX Code

function changeLanguage(language){

    var url = 'LanguageAction.action?request_locale='
        + language.value;
    var myAjax = new Ajax.Request(url, {
    method : 'post',
     onComplete: function(originalRequest){
          location.reload(true);        

         }
});

}

setting the language in request_locale and calling the action makes sure that, selected language will be automatically stored in session with the variable named,WW_TRANS_I18N_LOCALE

Spring RoutingDatasource:


package com.genral.utility;

import java.util.Locale;
import java.util.Map;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.interceptor.I18nInterceptor;
/**
 *
 * @author Sivaranjani D
 *
 */
public class RoutingDataSource extends AbstractRoutingDataSource {
    Locale locale = null;
    String language = "";
    LanguageType languageType = null;

    protected Object determineCurrentLookupKey() {

        if (ActionContext.getContext() != null) {
            Map<String, Object> session = ActionContext.getContext()
                    .getSession();

            if (session != null
                    && session
                            .containsKey(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)) {
                locale = (Locale) session
                        .get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE);
            }else{
                locale = new Locale("en");
            }

            language = locale.toString();

            if (language.equalsIgnoreCase("en"))
                languageType = LanguageType.English;
            else if (language.equalsIgnoreCase("ka"))
                languageType = LanguageType.Kannada;

        }
        return languageType;

    }

}

Generally the spring datasource should be implemented with the ThreadLocal concept. But here we are using the Struts2's ActionContext. Because, The ActionContext is thread local which means that values stored in the ActionContext are unique per thread. So whenever we are making a request to the database the language in session(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE) will be checked and that particular database will be chosen by RoutingDatasource.

  •  Now configure data source with the spring's RoutingDataSource class. Since each DB request goes with this datasource, we are linking our DynamicRoutingDataSource here


<bean id="dataSource" >
   <property name="targetDataSources">
      <map key-type="com.genral.utility.LanguageType">
         <entry key="English" value-ref="englishDataSource"/>
         <entry key="Hindi" value-ref="hindiDataSource"/>
         <entry key="Tamil" value-ref="tamilDataSource"/>
         <entry key="Kannada" value-ref="kannadaDataSource"/>
      </map>
   </property>
   <property name="defaultTargetDataSource" ref="englishDataSource"/>
</bean>

  <bean id="parentDataSource"

         abstract="true">
  <property name="driverClassName" value="${jdbc.driverClassName}" />
   <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<bean id="englishDataSource" parent="parentDataSource">
  <property name="url" value="${jdbc.url.english}" />
</bean>

<bean id="hindiDataSource" parent="parentDataSource">
  <property name="url" value="${jdbc.url.hindi}" />
</bean>

<bean id="tamilDataSource" parent="parentDataSource">
  <property name="url" value="${jdbc.url.tamil}" />
</bean>

<bean id="kannadaDataSource" parent="parentDataSource">
  <property name="url" value="${jdbc.url.kannada}" />
</bean>

LanguageType Class:



package com.genral.utility;
public enum LanguageType {
English,
Hindi,
Kannada,
Tamil,
Telugu
}

No comments:

Post a Comment