Wednesday, 1 August 2007

Working with cookies in Struts 2 - Part 2

Continuing from my earlier post, let's see how to add cookies to a HTTP response in an action class. Here also, I could figure out two ways by which it can be achieved -
  1. Use ServletActionContext to get HTTP response and set a cookie on it in the action

  2. Make the action implement ServletResponseAware interface and use the HTTP response object made available by the framework

Let's say we have an action class HelloWorld that needs to add a cookie named flash in the response.
Using the first option is pretty straightforward, here is how the code looks like -



public class HelloWorld extends ActionSupport {

private String username;

public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}

public String execute() throws Exception {
ServletActionContext.getResponse().addCookie(new Cookie("flash", getUsername()));
return SUCCESS;
}
}

To use the second option, the HelloWorld action needs to implement ServletResponseAware interface. This interface defines a single method,
void setServletResponse(HttpServletResponse response), which the framework, ServletConfigInterceptor to be precise, uses to carry out interface injection into the action at runtime. Here is how the code looks like -



public class HelloWorld extends ActionSupport implements ServletResponseAware {

private String username;
private HttpServletResponse response;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public void setServletResponse(HttpServletResponse response) {
this.response = response;
}

public String execute() throws Exception {
response.addCookie(new Cookie("flash", getUsername()));
return SUCCESS;
}
}

So far, so good. These options will allow us to do the needful. Still, I'm a little uncomfortable using any of these. Reason? Well, both options will tie up the actions to servlet environment, which , amongst others, will make unit testing difficult. Do we have a better option? Yes, in my opinion, we can use the interceptors feature of the Struts 2 framework to our advantage, to abstract this functionality into a separate interceptor and decouple the actions from Servlet API. More on it in the next post. Thanks for reading and stay tuned.



Saturday, 28 July 2007

Working with cookies in Struts 2

I have been working with Struts for a very long time now, in fact, I still clearly remember using perform method in the action classes :^) . And then, a few days ago, I got an opportunity to try my hand at Struts 2, the reincarnation of Struts, and at a first glance, it looks impressive, to say the least.

Coming to the subject, when I googled for how to work with cookies in struts 2, I could only find a couple of references, viz. struts-users mail archive link and CookieInterceptor javadoc . So, I'll take this opportunity to share whatever little I have picked up.

Let's divide this into two parts -
- Receiving cookies in an action
- Adding cookies to a response in an action

First, let's see how to receive cookies in an action. I could figure out two options by which it can be achieved. Well, there could possibly be other options available as well, but I'm sure you'll excuse me, as this post is based on my extremely limited knowledge of struts 2 that I could manage to gather in past couple of days. Please feel free to enlighten me if you know more about it. Both options need the CookieInterceptor to be configured for the action that needs to receive cookies. Here are the two options -

Option 1 - Filter cookies in the CookieInterceptor configuration and add properties with the cookie names to the action class
Option 2 - Make the action implement CookiesAware interface and receive a map that contains cookies received

Let's say we have an action class Greeter that expects a cookie named flash in the incoming request. Here is the action configuration for the CookieInterceptor. The param tag under interceptor-ref tag indicates the cookie name that is expected by the action.

<action name="Greet" class="com.omkarpatil.Greeter">
<result>/greet.jsp</result>
<interceptor-ref name="cookie">
<param name="cookiesName">flash</param>
</interceptor-ref>
</action>

To Use the first option, a field named flash with getters/setters needs to be added to Greeter action. The CookieInterceptor does it's magic at runtime to make the cookie available into the action. Here is the code snippet for Greeter action -


public class Greeter extends ActionSupport {
private String message;
private String flash;

public String getFlash() {
return flash;
}

public void setFlash(String flash) {
this.flash = flash;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String execute() throws Exception {
setMessage("Hello " + getFlash());
return SUCCESS;
}
}

To use the second option, the Greeter action needs to implement CookiesAware interface. CookiesAware interface defines one method void setCookiesMap(Map cookies), which the CookiesInterceptor uses to carry out interface injection into the action at runtime.


public class Greeter extends ActionSupport implements CookiesAware {
private Map cookiesMap;

public Map getCookiesMap() {
return cookiesMap;
}

public void setCookiesMap(Map cookiesMap) {
this.cookiesMap = cookiesMap;
}

public String execute() throws Exception {
// Do whatever you want to with the cookies map
return SUCCESS;
}
}

Well, that covers the "Receiving cookies into action" part. Onto the "Adding cookies to a response" in the next post. Stay tuned.