Extreme Java When vanilla Java is not enough

7Jul/110

vHost capabilities with Wicket

I started using Wicket because I liked how easy is to create SEO URLs and design-centric applications. One crazy feature I got working was customizing an application based on the vhost. The example I asked on StackOverflow used a fictional "abc.com" hosting with "abc.com.br" and "abc.com.pl" aliases.

The example works as this: all three vhosts are on the same codebase (i.e. the same "host" on Tomcat, with three aliases) and shows the same data. The difference between ".com", ".com.br" and ".com.pl" relies on how the data is shown to the user. There are two major country-related materials:

  1. Page design - ".com" must see an American tribute (USA is #1, American Flag, etc); ".com.br" must show Brazilian stuff (Samba, Soccer teams, etc); ".com.pl" shows Polish material. This was really easy, using a ResourceStreamLocator in my Wicket Application:
    getResourceSettings().addResourceFolder("");
    getResourceSettings().setResourceStreamLocator(
        new ResourceStreamLocator() {
      @Override
      public IResourceStream locate(Class clz, String path) {
        String host = ((WebRequest) RequestCycle.get().getRequest())
            .getHttpServletRequest().getServerName();
        String basePath = trimFolders(path);
        IResourceStream res = super.locate(clz, host + "/" + basePath);
        return (res != null) ? res : super.locate(clz, basePath);
      }
      private String trimFolders(String path) {
        return path.substring(path.lastIndexOf("/") + 1);
      }
    });
  2. Contextual URL mounting - this part was hard. Assume a page named "Page1". It must be accessed using "abc.com/page1", "abc.com.br/pagina1" and "abc.com.pl/strona1", but not with combinations (e.g. "abc.com/strona1"). After asking in SO, I got an answer from "biziclop" that lead me to the solution I wanted. It's a servlet filter mapping vhost to WicketFilter instances, isolating Wicket application instances (as biziclop sugested):
    @WebFilter(urlPatterns = "/*")
    public static class Filter implements IWebApplicationFactory,
                                          javax.servlet.Filter {
      private final Map filters = new HashMap();
      private final ThreadLocal hosts = new ThreadLocal();
      private FilterConfig config;
     
      @Override
      public void init(FilterConfig filterConfig) {
        this.config = filterConfig;
      }
      @Override
      public void destroy() {
        for (WicketFilter w : filters.values()) {
          w.destroy();
        }
        filters.clear();
      }
      @Override
      public void doFilter(ServletRequest request,
          ServletResponse response,
          FilterChain chain) throws IOException, ServletException {
        hosts.set(request.getServerName());
        try {
          getFilterForHost().doFilter(request, response, chain);
        } finally {
          hosts.remove();
        }
      }
      private WicketFilter getFilterForHost() throws ServletException {
        String host = hosts.get();
        if (!filters.containsKey(host)) {
          WicketFilter w = new WicketFilter() {
            @Override
            protected IWebApplicationFactory getApplicationFactory() {
              return Filter.this;
            }
          };
          w.init(config);
          filters.put(host, w);
        }
        return filters.get(host);
      }
      @Override
      public WebApplication createApplication(WicketFilter wf) {
        return new WicketApp(hosts.get());
      }
    }

Filed under: Java EE Leave a comment
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

(required)


*

No trackbacks yet.