Sunday, May 15, 2011

Managing multiple Domain and Sub Domain on Google App Engine for Same Application

Google App engine is great and at some time you may end up writing a app which gets popular and you want to use the same application for different domain and different sub-domain but show different site based on same underlying data.

e.g. you are writing a site www.indiadata.com which will show all data from india
Now say you got another domain www.delhidata.com or delhi.indiadata.com,(Delhi is a city of Country India) which shows data of delhi only. so you want to use same data saved in indiadata.com on delhidata.com and vice versa.
And this tutorial can help you to do exactly same thing

Technologies/Framework used
  1. Spring MVC 3.0+
Spring MVC's annotation based controller is quite handy to use in different situation where url remains same but some header parameter is different or url parameter is different. i.e. You can write two different controller for the same url which will be invoked based on what are the parameters etc.
You can read more sbout such Spring controllers here

Now lets understand how this will work.
  • First we need to identify whethere my application url is called as http://www.example.com/somepage or http://test.example.com/somepage
  • Once its identified we will modify the incoming request and let it to be handled by Spring dispatcher servlet
  • Different controller implementation for different urls
    • One Controller for http://www.example.com/somepage
    • One controller for  http://test.example.com/somepage

First Implement a filter to check every request

Implement a filter to identify domain or subdomain, lets call it DomainFilter


import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class DomainFilter implements Filter {
  
    private FilterConfig filterConfig;
 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws IOException, ServletException {
        MyServletRequestWrapper httpRequest = new MyServletRequestWrapper((HttpServletRequest)request);
         // Do not worry about MyServletRequestWrapper class, its implemented next
        String subDomain = getSubDomain(httpRequest);
  httpRequest.addHeader("subdomain", subDomain);
        filterChain.doFilter(httpRequest, response);
    }
    private String getSubDomain(HttpServletRequest httpRequest){
     //You can implement this function :) just to get www out of http://www.example.com or test out of http://test.example.com
  return "www";
    }
    public FilterConfig getFilterConfig() {
        return filterConfig;
    }

    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }
  
    public void destroy() {}
  
}


MyServletRequestWrapper : Class HttpServletRequest do not provide any method to modify Header in request so i extended HttpServletRequestWrapper to add this functionality.



public class MyServletRequestWrapper extends HttpServletRequestWrapper{

        private Map<String, String> headerMap;
        
        public void addHeader(String name, String value){
            headerMap.put(name, new String(value));
        }
        
        public MyServletRequestWrapper(HttpServletRequest request){
            super(request);
            headerMap = new HashMap<String, String>();
        }

        public Enumeration getHeaderNames(){
            
            HttpServletRequest request = (HttpServletRequest)getRequest();
            
            List list = new ArrayList();
            
            for( Enumeration e = request.getHeaderNames() ; e.hasMoreElements() ;)
                list.add(e.nextElement().toString());
            
            for( Iterator i = headerMap.keySet().iterator() ; i.hasNext() ;){
                list.add(i.next());
            }
            
            return Collections.enumeration(list);
        }
        
        public String getHeader(String name){
            Object value;
            if((value = headerMap.get(""+name)) != null)
                return value.toString();
            else
                return ((HttpServletRequest)getRequest()).getHeader(name);
            
        }
    }


Now apply this filter to all incoming request in web.xml



    <filter>
        <filter-name>SubSiteFilter</filter-name>
        <filter-class>com.next.fliters.DomainFilter</filter-class>
    </filter>    <filter-mapping>
        <filter-name>SubSiteFilter</filter-name>
        <url-pattern>*</url-pattern>
    </filter-mapping>



Now create a Spring Controller to handle www and other subdomain


    @Controller
    public class IndexController extends BaseController{
 //Follwoing controller will be called for url http://www.example.com/index.html
 @RequestMapping(value = "/index.html", method = RequestMethod.GET, headers="subdomain=www")
 public String mainIndexPage(Model model,HttpServletRequest request) {
  return "wwwindexpage";
 }
 
//Follwoing controller will be called for url http://test.example.com/index.html
 @RequestMapping(value = "/index.html", method = RequestMethod.GET, headers="subdomain=test")
 public String subsiteIndexPage(Model model,HttpServletRequest request) {
  return "subdomainindexpage";
 }

}


And now you are ready with your two different controller to handle two different url one with www and one with test.

Let me know if you end up with any problem

1 comment:

  1. The main advantage of multi-domain SSL certificate is that it protects a primary domain and at the most 99 Subject Alternative Names (also known as SAN) in a single certificate. In recent years, multi-domain certificates have become popular due to the advantages that they offer.

    ReplyDelete