JavaEE – Clustering support in JSF, Wicket, ZK, etc.

When a seasoned MVC framework developer starts writing code in component based framework like JSF, Wicket, ZK, etc. they fail to understand the basic differences between MVC and component based framework because they could write code which can work in non-clustered environment i.e. in single JVM deployment. When the same application is deployed in a clustered environment they start realizing the difference which will require lots of effort revisit all the code and make it compatible for clustering. I am going to talk about a few guidelines on making development (on top of component based framework ) cluster aware.

MVC vs. Component framework

MVC frameworks are stateless which means framework doesn’t store any information into HttpSession object, for example if you want to pass a value from one page to an another page you have to either use hidden tag or url query string. On the other hand component based frameworks are event driven programming which require components’ state to be preserved in HttpSession object. For example if you are using JSF, managed beans instance (in case of ZK it is ViewModel, in case of Wicket it is Page) are stored in HttpSession to re-use within the same session for further http request processing. A good part is you do not have to use hidden or query string to pass values instead same managed bean instance available across multiple http request but this good feature comes with some hidden issues.

Servlet Container Clustering

To make Java based web application work on clustered environment servlet containers have to replicate HttpSession object state across multiple server (i.e. multiple JVM). To transfer HttpSession object from one JVM to an another JVM servlet container have to serialize all the attributes stored inside the HttpSession. What happens if your managed bean does not implement Serializable interface or one of its member variables are not serializable? HttpSession replication will fail which you will notice only on clustered environment, during development (with single JVM) you will not notice this issue. Obviously then you will start making changes in your code to make sure all the managed beans are serializable to get it work in clustering environment.

Once you resolve the serialization issue you will start noticing performance and memory issues when you support high volume of concurrent users. To avoid memory issue you need to make sure all managed beans are small i.e. only required objects are declared as member variable in other word keep only mandatory values as member variables which are absolutely required to retain the state of Bean or Model. Wherever is possible use temporary variables within methods which will not be serialized.

Checklist

  1. All beans and models should be serializable.
  2. Size of the each bean and model should be as minimal as possible.

I used the code below to capture serializable issue during development.

Here is the servlet filter class.

package org.webmoli.servlets;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Enumeration;

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.HttpSession;

public class HttpSessionFilter implements Filter {

	private boolean testSerializability = true;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		testSerializability = Boolean.valueOf(filterConfig.getInitParameter("testSerializability"));
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
			ServletException {
		chain.doFilter(request, response);
		// this block of code ensures all the values in the HttpSession object are serializable to ensure it works on
		// clustered environment
		if (testSerializability) {
			HttpServletRequest httpServletRequest = (HttpServletRequest) request;
			HttpSession httpSession = httpServletRequest.getSession(false);
			if (httpSession != null) {
				Enumeration<String> enumeration = httpSession.getAttributeNames();
				while (enumeration.hasMoreElements()) {
					Object value = httpSession.getAttribute(enumeration.nextElement());
					if (value != null) {
						try {
							new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(value);
						} catch (Exception exp) {
							System.err.printf("Error while serializing session object: {}", exp.getMessage());
							// exp.printStackTrace();
						}
					}
				}
			}
		}
	}

	@Override
	public void destroy() {

	}

}

Here is the web.xml entry

	<filter>
		<filter-name>HttpSessionFilter</filter-name>
		<filter-class>org.webmoli.servlets.HttpSessionFilter</filter-class>
		<init-param>
			<param-name>testSerializability</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>HttpSessionFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

2 Responses to JavaEE – Clustering support in JSF, Wicket, ZK, etc.

  1. mohanmca says:

    Good!
    Could you consider converting above code as servlet filter, so can be configurable in web.xml for any application.

  2. Venkat says:

    Mohan – thanks for the feedback. Modified post with actual servlet filter code also added web.xml entry.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: