Wednesday, April 20, 2005

StrutsTestCase and Tokens

How does one get around the usage of Struts tokens when unit testing using StrutsTestCase? If the action class under tests for duplicate submissions using tokens,

if(isTokenValid(request) == false) {
// don't perform the action and route the user
// to an appropriate location
}

it'll always fail. This is because, the token is set in the request by the tag and of course when running a StrutsTestCase, the JSP isn't involved.

The application functions correctly, however, I cannot run my unit tests :(

Thursday, April 07, 2005

Clustering mutable objects

One of things a clusterable application server (for example, Web Logic) does for an application is to broadcast objects placed in the user's session. This happens (at least with Web Logic) whenever the application invokes the setAttribute method of the HttpSession interface. This has a subtle impact when the thing being placed in the session is a mutable object. To explain, first consider a simple (non-mutable) example

1: String name = "John";
2: session.setAttribute("username", name);

The application server will serialize the value associated with the key username to all the nodes in the cluster. Now suppose that the node executing the above steps turns around and changes the value of name. IOW

1: String name = "John";
2: session.setAttribute("username", name);
..
15: name = "Mary";
16: String sessionValue = (String)session.getAttribute("username");

Since Java passes a copy of a reference to a method call, sessionValue is guaranteed to be John -- on all the nodes. No harm. No foul.

Now consider placing a mutable object such as a java.util.List in the session.

1: List cart = new ArrayList();
2: session.setAttribute("shoppingcart", cart);

Just as with the String before, this will get propagated to all the nodes in the cluster. Now suppose the cart is updated in one of the nodes:

1: List cart = new ArrayList();
2: session.setAttribute("shoppingcart", cart);
..
19: cart.add(aLineItem);
..
// More business logic
25: List sessionValue = (List)session.getAttribute("shoppingcart");
26: System.out.println("Cart size = " + sessionValue.size());

Now, line 26 above will display different values depending on the node on which it was executed. The node which added the item to the cart will display Cart size = 1 while the others will display Cart size = 0.

This is bad! This can be avoided if we place an item in the session as the last step of responding to a user request. Application development and application deployment are -- in large part -- independent activities. This is an instance where the developer needs to be aware that (s)he is developing an application that's going to be deployed to a clustered environment.

Tweety thoughts

    follow me on Twitter