Gridsphere 3.0 Portal and Spring MVC Portlets
The sample Portlet of this Tutorial is developed and tested on Tomcat 5.5 with gridsphere 3.0 and Spring 2.0.
Prerequesites:
- Basic knowledge about Spring MVC Web Applications and JSR-168 Portlet development
- Spring 2.0
- Remove older versions of Spring from your shared/lib directory.
- Ant (developed with version 1.7.0 )
Basic project structure:
|_ _ build
|
|_ _ src
|
|_ _ webapp
| |
| |_ _ WEB-INF
| |_ _ classes
| | |
| | |_ _ log4j.properties
| |
| |_ _ context
| | |_ _ applicationContext.xml
| | |
| | |_ _ portlet
| | |
| | |_ _ person.xml
| |
| |_ _ dtd
| |
| |_ _ jsp
| |
| |_ _ lib
| |
| |_ _ persistence
| |
| |_ _ tags
| |
| |_ _ portlet.xml
| |
| |_ _ web.xml
|
|_ _ build.properties
|
|_ _ build.xml
web.xml:
Place the following code in your web.xml:
<!-— Context Parameter -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context/applicationContext.xml</param-value>
</context-param>
<!-— Listeners -->
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-— ViewRenderer Servlet -->
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
<!-— Spring MVC Portlet Mapping -->
<servlet>
<servlet-name>person</servlet-name>
<display-name>person Wrapper</display-name>
<description>Automated generated Portlet Wrapper</description>
<servlet-class>org.gridsphere.provider.portlet.jsr.PortletServlet</servlet-class>
<init-param>
<param-name>portlet-class</param-name>
<param-value>org.springframework.web.portlet.DispatcherPortlet</param-value>
</init-param>
<init-param>
<param-name>portlet-guid</param-name>
<param-value>spring-portlet-sample.person</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>person</servlet-name>
<url-pattern>/person/*</url-pattern>
</servlet-mapping>
<!-— Gridsphere PortletService Mapping -->
<servlet>
<servlet-name>PortletServlet</servlet-name>
<servlet-class>org.gridsphere.provider.portlet.jsr.PortletServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PortletServlet</servlet-name>
<url-pattern>/jsr/gridsphereSpringPortlets</url-pattern>
</servlet-mapping>
<!-— Tag Libraries -->
<taglib>
<taglib-uri>http: <taglib-location>/WEB-INF/tags/spring.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http: <taglib-location>/WEB-INF/tags/portlet.tld</taglib-location>
</taglib>
The Log4jConfigListener loads the log4j.properties and is responsible for initialization of Log4j. The location of the log4j.properties file is supplied by the context-parameter log4jConfigLocation. Set log4j.logger.org. springframework=DEBUG for debugging of spring.
The declaration of the ContextLoaderLIstener is important because this Listener loads the application context from the location which is delivered by the ContextConfigLocation context parameter.
The ViewRendererServlet is a bridge servlet, mainly for the Portlet MVC support. It is responsible for rendering the view, represented by the V in MVC.
Unlike JSR-168 Portlets Spring MVC Portlets also have to be declared and mapped in the web.xml. Gridspheres PortletServlet is referenced through the servlet-class property. As you can see, the content of the person portlet's portlet-class parameter is not the portlet class itself, but the Spring Framework's DispatcherPortlet. Its major task is to enable the cooperation of the Spring Framework and the Portal. It accepts all requests, prompts for HandlerMappings and invokes the HandlerAdapter if necessary. As the last parameter the portlet-guid param is set which references the portlet name, defined in the configuration file.
The referenced Tag libraries are important for the rendering of the JSPs.
portlet.xml:
Place the following code in your portlet.xml:
<portlet>
<portlet-name>person</portlet-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/context/portlet/person.xml</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>Person</title>
</portlet-info>
</portlet>
Apart from the portlet-class mapping and the init-param contextConfigLocation this is just an ordinary portlet declaration.
As already explained in section 'web.xml' the portlet-class maps the DispatcherPortlet.
Again a contextConfigLocation init-param is supplied. It contains the location of the portlet's own spring configuration file. The reason for this is the possibility of adding more than one portlet to your application. So the context file referenced in the 'web.xml' contains global configurations for all portlets of the application while the context file defined in the portlet declaration contains configurations especially for this portlet.
applicationContext.xml:
Place the following code into your applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "- "../dtd/spring-beans.dtd">
<beans>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages</value>
</list>
</property>
</bean>
<!-- Default View Resolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="cache" value="false"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- Abstract Default Exception Handler Bean -->
<bean id="defaultExceptionHandlerTemplate" abstract="true"
class="org.springframework.web.portlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="defError"/>
<property name="exceptionMappings">
<props>
<prop key="javax.portlet.PortletSecurityException">notAuthorized</prop>
<prop key="javax.portlet.UnavailableException">notAvailable</prop>
</props>
</property>
</bean>
<bean id="portletNameInterceptor" class="org.gridsphere.spring.portlets.PortletNameInterceptor"/>
</beans>
As mentioned in the last section, the applicationContext.xml contains the global configuration of the application.
The first bean references the messages.properties file. Don't forget to add a file with the locales if you want to be able to display the portlet in different languages or if your default language isn't english.
The next bean defined in the applicationContext.xml is the viewResolver which is responsible for displaying the View. The prefix and suffix properties define the path to the files that should be displayed and the type of the files, in this case JSP. The property viewClass is set to the JstlView Class of the Spring Framework. This class enables explicit JSTL support and is essential when using Spring"s locale and message source implementation.
The defaultExceptionHandlerTemplate bean references the SimpleMappingExceptionResolver which assigns exceptions to JSPs that contain error messages. You can see the mapping of the exception type to the corresponding error page as the prop tags in the exceptionMappings property.
The portletNameInterceptor bean is a custom class defined for this project and will be explained later.
person.xml:
Create a XML-file named person.xml and copy and paste the following code:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "- "../../dtd/spring-beans.dtd">
<beans>
<!-- Controllers -->
<bean id="personController" class="org.gridsphere.spring.portlets.PersonController">
<property name="sessionForm" value="true"/>
<property name="commandName" value="person"/>
<property name="commandClass" value="org.gridsphere.spring.portlets.util.Person"/>
<property name="formView" value="person"/>
<property name="successView" value="person"/>
</bean>
<!-- Handler Mapping -->
<bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view"><ref bean="personController"/></entry>
</map>
</property>
</bean>
<bean id="defaultExceptionHandler" parent="defaultExceptionHandlerTemplate"/>
</beans>
A bean with the id PersonController is defined as the first bean and is kind of the heart of the Spring MVC Portlet. Its associated class is the PersonController class which is a custom class which is a subclass of Spring's SimpleFormController. Because of this there are several properties that have to be set for the so called Spring Binding. Spring binding is nothing but ordinary data binding. Spring binds the incoming form data to a Plain Old Java Object (POJO).
The sessionForm property is set to true, which means that Spring uses the same bean instance for the duration of the session. If set to false it would create a new instance for every request.
The commandName property is the name of the object referenced by the commandClass property. You can consider it as some kind of unique Identifier for the JavaBean which is bind to the form.
The formView and the successView property define the JSPs that should be displayed to the user. The formView is mapped to show the form when the controller initially loads portlet and when the form has been submitted with invalid data. In case of successful data transmission the JSP mapped in the succesView property is loaded.
Optionally you can add a validator property for validation of field entries of your form.
The main purpose of the portletModeHandlerMapping is to map the portlet modes to the beans defined in your context. Due to Spring MVC concept mapping is essential for running a Spring portlet. The Spring Framework supports the portlet modes view, edit, configure and help. But it's also possible to implement custom modes. In this case the portlet only supports the view mode because this is sufficient to show the basic functionality of Spring MVC Portlets.
The last bean is the defaultExceptionHandler mapping the defaultExceptionHandlerTemplate of the applicationContext.xml through its parent attribute.
The POJO:
At first we have to write a simple bean called Person. As you can see there is nothing special about the class, just some getters and setters. This is the bean the form data will be binded to.
public class Person implements Serializable {
private String firstName;
private String lastName;
private String email;
public Person(){
}
public void setFirstName(String firstName){
this.firstName = firstName;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
public void setEmail(String email){
this.email = email;
}
public String getFirstName(){
return this.firstName;
}
public String getLastName(){
return this.lastName;
}
public String getEmail(){
return this.email;
}
}
The Controller:
You can skip this paragraph if you are already familiar with developing Spring web applications.
As you may have already realized the Controller is the C in the MVC. That indicates the important role it plays in a Spring application. A controller handles the input event from the user interface, often via a registered handler or callback, accesses the model, possibly updating it in a way appropriate to the user's action ¹
.
The controller used in this sample application is the PersonController which extends the SimpleFormController. The SimpleFormController provides a configurable form and success views, and an onSubmit chain for convenient overriding. Automatically resubmits to the form view in case of validation errors, and renders the success view in case of a valid submission ²
.
Let's take a look at the source code:
public class PersonController extends SimpleFormController {
public ModelAndView onSubmitRender(Object command, BindException errors) throws Exception {
Person person = (Person) command;
String newPerson = person2table(person);
ModelAndView mav = new ModelAndView("person");
mav.addObject("person", person);
mav.addObject("newPerson", newPerson);
return mav;
}
public String person2table(Person person){
if(person != null){
String person2table = "<tr>";
person2table = person2table + "<td><b>Last name:</b>" + person.getLastName();
person2table = person2table + person"</td></tr>";
person2table = person2table + "<tr><td><b>First name:</b> ";
person2table = person2table + person.getFirstName() + "</td></tr>";
person2table = person2table + "<tr><td><b>Email:</b> " + person.getEmail();
person2table = person2table + "</td>";
person2table = person2table + "</tr>";
return person2table;
} else {
return "<tr><td>leer</td></tr>";
}
}
}
As mentioned in the preceding paragraph the PersonController extends the SimpleFormController. The SimpleFormController has various methods for handling the submission of the form. The most important methods are onSubmitRender and onSubmitAction, which correspond to the portlet modes Action and View. In this case it is sufficient to overwrite the onSubmitRender method because we just want to display the data entered by the user below the form.
The onSubmitRender method takes the bean to which the form data is binded as its first argument and a BindException as the second argument. A BindException is thrown when binding errors occur, e.g. the class to which the data is binded is not found. The method returns a ModelAndView object, which maps the model to the view.
At first a casting to the Person class is performed which is the data binding bean for the Person portlet. Then the person2table method is called. As the name suggests this method expects a person object as parameter and returns a String with all information about the person respectively all information that is stored in the person object. In short it's the textual representation of the form data in a table if the supplied Person object is not null. The returned String is stored in the variable newPerson.
After that a new ModelAndView is created. The given model is person which is the same as before, but we have to return one and we want to display the data on the same page. As already mentioned this class is the holder for both, model and view in the Spring MVC framework. In this case the constructor is given the name of the view as a parameter. After that a new instance of Person is supplied to the ModelAndView to display a plain form. This is done by calling the addObject method of the ModelAndView class and passing a key-value-pair as arguments. This method is called once for passing the instance of Person to get a plain form and the second time to add the newPerson String with the form data to the JSP page.
The View:
The view in Spring MVC Portlets is mostly represented by Java Server Pages as it is in this case.
<%@ page contentType="text/html" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http: %>
<%@ taglib prefix="portlet" uri="http: %>
<%@ taglib prefix="spring" uri="http: %>
<h1>Enter your personal data</h1>
<form method="post" action="<portlet:actionURL/>">
<table border="0" cellpadding="4">
<tr>
<th>First Name</th>
<spring:bind path="person.firstName">
<td width="20%">
<input type="text" name="firstName" value="<c:out value="${status.value}"/>">
</td>
</spring:bind>
</tr>
<tr>
<th>Last Name</th>
<spring:bind path="person.lastName">
<td width="20%">
<input type="text" name="lastName" value="<c:out value="${status.value}"/>">
</td>
</spring:bind>
</tr>
<tr>
<th>Email</th>
<spring:bind path="person.email">
<td width="20%">
<input type="text" name="email" value="<c:out value="${status.value}"/>">
</td>
</spring:bind>
</tr>
<tr>
<th colspan="2">
<button type="submit">Go</button>
</th>
<spring:hasBindErrors name="person">
<p style="color:#A00000">Please fix all errors!</p>
</spring:hasBindErrors>
</tr>
</table>
</form>
<table border="0">
${newPerson}
</table>
<p style="text-align:center;">
<a href="<portlet:renderURL portletMode="view"/>">- HOME -</a>
</p>
Since we deal with a portlet the form data can't be sent to a URL. We have to tell the form where we want the data to be sent to. The portlet Tag Library comes with the <portlet:actionURL/> Tag which creates a URL that points to the current portlet and triggers an action request ³
.
The form is just an ordinary HTML web form except of the <spring:bind> tags. As already explained in the last section the binding enables you to bind the input fields of a form to the properties of a bean. The data binding is set using the path attribute. The path is a combination of the commandName set in bean definition and the property you want to bind the field to.
Through the status object you can get information about errors, property values and expressions to use when rendering. In this case only status.value is used because we don't use a Validator class to check if the fields are corretly filled in. The status.value variable returns the actual value of the bean or property. The <spring:hasBindErrors> tag binds all the errors for the object and its properties and returns them as a java.util.List.
After the HTML form there is an empty table with the newPerson parameter. If you initially load the page there will be just an empty table which you could see looking if you would look at the source code of the rendered page. But after submitting the page, this parameter is also submitted to the page and the table will contain the data submitted by the user.
This is what the resulting portlet should look like:

Download the sample application and unzip it to your $GRIDSPHERE_HOME/projects directory. Then run ant install to deploy it to your web server.
sample application
Important note:
If you start to devlop your own Spring MVC Portlets in Gridsphere copy the portlet.tld from $GRIDSPHERE_HOME/webapps/gridsphere/META-INF/tlds to the tags directory of your application.
IMHO it is not necessary to define spring portlets in web.xml. Why do you need it? Is it a requirement of GridSphere 3?