Spring provides a flexible Portlet MVC framework. By using it in our WebSphere portal application development, we benefited not only from the Portlet MVC framework itself, but also from other features such as IoC supported by Spring.
In this post I would like to share a problem we faced when integrating Spring Portlet MVC framework with WebSphere Portal, as well as our solution.
As defined in the JSR-286 specification, a normal client to server action request is separated into two phases: action phase and render phase. Normally, we can control the process in render phase by setting render parameters in action phase. Unfortunately, the render parameters can only be of String type. The ModelMap provided by Spring can be used to break this limitation. At the end of the process of action phase, Spring will put the ModelMap, which contains all the objects returned by the methods with @ModelAttribute, into the portlet session. We can fetch these objects from the ModelMap during the render phase, no matter which type it is of.
The problem we found is that once an action request is processed for a portlet, all the methods with @ModelAttribute will not be executed again before any render request for the same portlet. It means even after we clicked the refresh button, we will see the same page as before, although the information in the backend such as database is actually changed. This is obviously not what we’re expecting.
The root cause of this problem is that Spring is using a render parameter to indicate whether it should fetch the ModelMap from portlet session (It is called IMPLICIT_MODEL_RENDER_PARAMETER). And WebSphere Portal server will encode this render parameter into the URL in order to keep the view status. This caused when the page is requested again, the parameter is sent back to the server as a request parameter, misguiding Spring to the ModelMap stored in portlet session.
The solution is not complicated. Because Spring only stores the ModelMap into session if there’s really something in the map. Clearing the ModelMap after the action phase process finished can simply solve this problem. However, we lost the ability to pass an object from action phase to render phase. Another solution is to remove the session attribute of the ModelMap programmatically, so Spring cannot get it from session again when processing the render request.