Friday, March 27, 2009

Dynamic link in Spring portlet mvc

The biggest problem in portal applications written using JSR-168 and Ajax is the fact that all links to portlets within your portal must be server-side generated. This is usually achieved using the “” and/or “” tags in your JSP views or by using the Portlet API directly. These tags and the Portlet API allow you to encode arbitrary parameters that are then supplied to the target portlet. Unfortunately, if you use Ajax, these parameters are usually dynamic (e.g. an id of a row that the user has selected in a Ajaxified table widget) and are therefore unknown during server-side link generation.

This article depicts a resolution of this problem for an application that is using IBM WebSphere Portal 6.0 as it’s runtime. The application also uses Spring 2.5.6 and relies heavily on Spring Portlet MVC. The Ajax aspect was implemented using Dojo toolkit 1.2.3.

The application described here uses the following set of frameworks (only those relevant to this article listed):

* Spring 2.5.6
* Dojo 1.2.3

This is the desired end result:

1. A user is presented the initial view of the portlet (list view). This list view has an embedded dojox.grid.DataGrid dojo widget that fetches data from the server as necessary.
2. The user can select one row from the dojo grid widget. At that time a “Details” button below the widget is enabled.
3. When the user clicks the “Details” button the user is shown a different portlet view (update view) with details of the item selected in the dojo grid widget allowing the user to change something and submit the information so it can be updated in a database.
4. After submit the user is again shown the list view.

For this to work, the “Details” button needs to notify the application which item in the grid was selected. This cannot be embedded in a
since the item id is not known when this “list” view is generated on the server.

The solution uses Spring Portlet MVC, but the same idea can be applied to other situations as well.

The first thing that needs to be created is a Command class. A Spring command is a POJO that is used to pass information from a HTML FORM to a Spring MVC controller class:


1. package com.spmvc.command;
2.
3. public class MyCommand {
4. private Integer itemId;
5.
6. public Integer getItemId(){
7. return this.itemId;
8. }
9. public void setItemId(Integer id){
10. this.itemId = id;
11. }
12. }

package com.spmvc.command;

public class MyCommand {
private Integer itemId;

public Integer getItemId(){
return this.itemId;
}
public void setItemId(Integer id){
this.itemId = id;
}
}

The itemId field will be used to store the ID of the item selected in the grid. In my application, this ID represents the value of the primary key in the database table used to store the grid items. I know this value because the data that the grid widget fetches from the server includes it.

Now we need to create the button. The following is an excerpt from my list view JSP:



1. <%@page session="false" contentType="text/html; charset=UTF-8"
2. pageEncoding="UTF-8" import=""%>
3. <%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
4. <%@taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
5. <%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
6.
7.
8.
18. ...
19.
20.
21.
22.

23. ...
24.
25.
26.
28.

29. ...



Important parts:

* 20-22 : Here we generate the link to our portlet. As you can see, we are telling the portlet API to generate us a link that will invoke the Action phase of portlet processing with one parameter named “action”. This parameter is used by Spring Portlet MVC to determine the controller that will be used to handle this action request.
* 24-28 : A small form is used to submit our request. Notice that the form has the generated link as the action attribute. There is also a hidden field that will carry the ID of the selected grid item.

The idea here is to generate a link to a specific Spring Portlet MVC controller (that is what we know during server-side processing of this JSP) and use a form to send the ID of the currently selected grid item (that is the what we don’t know during server-side processing).

The hidden form field is actually updated using a JavaScript function attached to our grid widget. The code is unimportant for this article and trivial - hence, it is not presented here.

Next, let’s see the Spring Portlet MVC controllet used for this form:


1. package com.spmvc.controller;
2.
3. import com.spmvc.command.MyCommand;
4.
5. import javax.portlet.ActionRequest;
6. import javax.portlet.ActionResponse;
7.
8. import org.springframework.validation.BindException;
9. import org.springframework.web.portlet.mvc.SimpleFormController;
10.
11. public class UpdateLinkHelperController extends SimpleFormController {
12. protected void onSubmitAction(ActionRequest request,
13. ActionResponse response,
14. Object command,
15. BindException errors) throws Exception {
16.
17. MyCommand cmd = (MyCommand)cmd;
18.
19. request.getPortletSession(true).setAttribute("itemId", cmd.getId());
20.
21. response.setRenderParameter("action", "update");
22.
23. response.setRenderParameter("form-submit", Boolean.FALSE.toString());
24. }
25. }



Important parts:

* 19 : The ID of the item that was selected and that was sent to the controller via the hidden form field is now stored in session. Obviously, this should be a small piece of information, like a single Integer in this case.
* 21 : This causes Spring Portlet MVC to use a different controller next in the chain of events. More about this a little later.
* 23 : This is a little “hack” for Spring Portlet MVC and the way it handles form submissions.

As we will show later on in Spring configuration, a request/render parameter with the name “action” is used by the Spring Portlet MVC to determine the controller to invoke for a particular request. Since Portlet requests are handled (as specified by the JSR-168 ) in two distinct phases: action and render, Spring Portlet MVC allows us to use different controllers for each of the two phases.

This is exactly what we are doing here. We use our UpdateLinkHelperController for the action phase, during which we store the ID in session, and we use a different controller for the render phase. This render phase controller is again just a simple form controller that sends us the form used by the user to input information - the only quirk here is the fact that this render phase controller uses it’s standard formBackingObject method to extract the ID from the session and prepares the command object for the form:


1. ...
2. public class UpdateController extends SimpleFormController {
3. ...
4. protected Object formBackingObject(PortletRequest request) throws Exception {
5. Integer id = (Integer) request.getPortletSession(true).getAttribute("itemId");
6. // TODO... do something with id. e.g. load data from database...
7. // Optionally, remove the id from session if not needed...
8. // And, always check if id is null just in case...
9. }
10. ...
11. }

...

Before we go on, one more thing to explain: Why do we set the “form-submit” render parameter in our controller (see line 23 in source block before last)? SimpleFormController sets this parameter to “true” just when it enters the action phase. If we don’t set it back to “false”, then our render phase controller will think that it was invoked as a render phase of a successful form submit. Technically that is true, but we want it to think like it was called in order to show the user a form used to gather user input. That is why we need to set the “form-submit” parameter to false.

The only thing left to show is the Spring portlet configuration file:


1.
2. 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
6.
7.
8.
9.
10.
11.
12.
13.

14.
15.
16. 17. class="org.springframework.web.portlet.handler.PortletModeParameterHandlerMapping">
18.
19.
20.
21.
22.

23.

24.
25.
26.
27.
28.
29.
30.

31.
32.
33.

34.
35.
36.

37.
38.
39.

40.

41.

42.

43.

44.




Note the following:

* 11 : This is the form that gets displayed. In this case it would be “details/Details.jsp”.
* 28 : This key must be the same as the value of the action parameter used in the actionURL tag in the JSP file (line 4 of the second code block).
* 35 : This is how Spring knows what controller to use for the render phase. See that we specify “update” for the “action” parameter in our UpdateLinkHelperController.

REFERENCES

* Dojo Toolkit
* Spring framework
* JSR-168