Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The following is an example subclass that allows for type safe access to a User object stored in session:

Code Block
languagejava
titleActionBeanContext subclass
public class MyAppActionBeanContext extends ActionBeanContext { 
	public void setUser(User user) { 
		getRequest().getSession().setAttribute("user", user); 
	} 

	public User getUser() { 
		return (User) getRequest().getSession().getAttribute("user"); 
    } 
} 

Now that you have your own ActionBeanContext you'll need to tell Stripes to use it. The easiest way is to drop your class into an extensions package (see Extensions). Alternatively, you can add the following initialization parameter to the Stripes Filter in your web.xml:

Code Block
xml
languagexml
titleConfiguring your ActionBeanContext
<init-param> 
	<param-name>ActionBeanContext.Class</param-name> 
	<param-value>com.myco.MyAppActionBeanContext</param-value> 
</init-param> 

...

Now, the ActionBeanContext that gets set on your ActionBean will always be a MyAppActionBeanContext. You'll still have to cast the context object that you receive in your ActionBean, but thanks to a new feature in Java 1.5 called co-variant return types, you can at least do it once, and not litter your code with casts.

Code Block
languagejava
titleUsing a co-variant return type in your ActionBean
public class MyActionBean implements ActionBean { 
	private MyAppActionBeanContext context; 

	/** Interface method from ActionBean. */ 
	public setContext(ActionBeanContext context) { 
		this.context = (MyAppActionBeanContext) context; 
	} 

	/** Interface method from ActionBean, using a co-variant return type! */ 
	public MyAppActionBeanContext getContext() { 
		return this.context; 
	} 

... 
} 

...

But wait, there's more. Because the ActionBeanContext is attached to your ActionBean, and your ActionBean is dropped into a request attribute, you now have two ways of accessing things stored in session. On a JSP:

Code Block
xml
languagexml
<div>${user} == ${actionBean.context.user}</div> 

...

With just a little bit more work, you can make your ActionBeans completely testable. Using our MyAppActionBeanContext example above, we can create an abstract class that our ActionBeanContext will extend, and which our ActionBeans will use. Let's refactor a bit:

Code Block
languagejava
titleMyAppActionBeanContext.java
public abstract class MyAppActionBeanContext extends ActionBeanContext { 
	public abstract void setUser(User user); 
	public abstract User getUser(); 
} 

Our "real" class would look much the same as before, but perhaps this time we'd name it differently:

Code Block
languagejava
titleMyAppActionBeanContextImpl.java
public class MyAppActionBeanContextImpl extends MyAppActionBeanContext { 
	public void setUser(User user) { 
		getRequest().getSession().setAttribute("user", user); 
	} 

	public User getUser() { 
		return (User) getRequest().getSession().getAttribute("user"); 
	} 
} 

And then, we create out test ActionBeanContext:

Code Block
languagejava
titleMyAppActionBeanContextTestImpl.java
public class MyAppActionBeanContextTestImpl extends MyAppActionBeanContext { 
	private User user; 

	public void setUser(User user) { this.user = user; } 

	public User getUser() {return this.user; } 
} 

...

An example of flash scope usage is non-error messages functionality in Stripes. The ActionBeanContext has a getMessages() method that returns a list to which messages may be added. This list is stored in flash scope so that the messages are available to the current request (should the ActionBean forward to a page) and in the next request (should the ActionBean redirect to a page). The code looks like this:

Code Block
languagejava
titleExample usage of FlashScope
public List<Message> getMessages(String key) { 
	FlashScope scope = FlashScope.getCurrent(getRequest(), true); 
	List<Message> messages = (List<Message>) scope.get(key); 

	if (messages == null) { 
		messages = new ArrayList<Message>(); 
		scope.put(key, messages); 
	} 

	return messages; 
} 

...

By default ActionBeans are not put in flash scope. This is partly for backwards compatibility reasons, and partly because it just isn't necessary to do it all the time! That doesn't mean it's hard to do though. If you're using the standard RedirectResolution it's as simple as chaining one more method call:

Code Block
languagejava
return new RedirectResolution("/some/page.jsp").flash(this); 

Even if you're redirecting some other way, it's still very easy:

Code Block
languagejava
// From within the ActionBean 
FlashScope.getCurrent(getContext().getRequest(), true).put(this); 

...

Lets say you called this method in one of your ActionBeans:

Code Block
languagejava
public void addRecipe(HttpServletRequest request, String message) { 
	FlashScope fs = FlashScope.getCurrent(request, true); 
	List<String> messages = (List<String>) fs.get("recipes"); 

	if (messages == null) { 
		messages = new ArrayList<String>(); 
		fs.put("recipes", messages); 
	} 

	messages.add(message); 
} 

Then you redirected to another ActionBean which forwards to a JSP. This is how you access the FlashScope in your JSP:

Code Block
xml
languagexml
<c:forEach var="recipe" items="${recipes}"> 
	<div class="recipe_name">${recipe.name}</div> 
</c:forEach> 

...