CHAPTER 4

image

Spring Portlets

Although not required for the certification exam, spring portlets are covered in this book because a lot of medium-sized companies tend to favor portal applications, which come with a set of modules already implemented. Companies may also hire developers to provide the customized functionality via pluggable components. Usually, these portal applications are licensed and supported, which is an advantage when things do not go exactly as planned, because you have direct contact with a team of experts that can help you with problems specific to the software.

Portlets are pluggable web components used when creating a portal, which is a complex web-based application that provides personalization, authentication, and customizable content aggregation from multiple sources. A portlet is a Java-based web component; its lifecycle is managed by a portlet container, which processes requests and generates dynamic content.1 Each portlet produces a fragment of markup that is combined with the markup of other portlets in the context of a composite portal page. On enterprise application servers, a new war archive is deployed on a server, either manually by copying it into a deployment directory, or by uploading it using a manager application. A standard Java portlet should be deployable on any portlet container2 that complies with the standard.

The advantage of using portlets is that the developer has to only handle the implementation of the logic inside a portlet; the portal server takes care of the rest, such as building and securing the page. Although this seems restrictive, the value of a portal application is the control that is given to administrators and users.

A portlet (or a collection of portlets) behaves as a web-based application per-se, and it can be aggregated to build more complex web applications—portals. Portal applications are as widely used as servlet applications and the design of such applications comes in two flavors:

  • Portlets provide small units of functionality and are aggregated by the portal server into a larger application (see Figure 4-1).

    9781484208090_Fig04-01.jpg

    Figure 4-1. Diagram of portlets as units of a single-page portal application

  • Whole applications can be written to reside in only one or a few portal pages (see Figure 4-2).

    9781484208090_Fig04-02.jpg

    Figure 4-2. Diagram of a multipage portal application

Choosing which approach to use depends on the requirements of the application and the number of different functionalities that the application must provide. For example, a university’s portal application is made of multiple pages, and each of those is made of multiple portlets with functionality related to a common domain. But a smaller application—a blog, for example—does not need multiple pages; the whole application can fit into one portal page.

Liferay Community Edition version 6.2-ce-ga43 is used to run the examples in this chapter (Figure 4-3 shows the official Liferay site to help you easily see what you need to download). Choices are made by taking compatibility with Spring into consideration, as well as how practical development and deployment will be. Every portal application requires specific configurations, but Liferay allows high decoupling between portal and application configuration, which is quite an important feature, as you will soon discover.

9781484208090_Fig04-03.jpg

Figure 4-3. Liferay Portal version to download: Community Edition Bundle with Tomcat

Spring provides an MVC framework for the JSR-168 and JSR-268 portlet development. This framework tries, as much as possible, to mirror the Web MVC framework, and also uses the same underlying view abstractions and integrations technology to make portlet development more practical.

Portlet Basics

Portlet workflow is different from servlet workflow because it involves two distinct phases: an action phase and a render phase. The action phase is executed only once; this is the phase where backend logic is executed. During the render phase, the response that gets sent back to the user is produced. So there is a separation between activities that affect the state of the system and the activities that generate data to be displayed.

Figure 4-4 depicts the difference between MVC servlet handling and MVC portlet handling when using Spring.

9781484208090_Fig04-04.jpg

Figure 4-4. Spring MVC portlet handling

In the early versions of Spring MVC framework, implementing a controller class in a servlet-based application meant extending the o.s.web.servlet.mvc.AbstractController class (or implementing the org.springframework.web.servlet.mvc.Controller interface) and overriding the handleRequest() method, which is called by DispatcherServlet. Starting with Spring 3.0, this was no longer necessary, because annotations (@Controller and @RequestMapping) are used to provide a more flexible and practical way of working with controllers.

There is an equivalent Spring class for portlets that should be extended to create a portlet: the org.springframework.web.portlet.mvc.AbstractController class (and an equivalent interface org.springframework.web.portlet.mvc.Controller).

The handleActionRequest() and the handleRenderRequest() methods should be overridden; the org.springframework.web.portlet.DispatcherPortlet handles their invocation.

Since Spring 3.0, annotations have made things easier for development of portlets too. @Controller is used to annotate a portlet controller, @RenderMapping is used to annotate a render method, and @ActionMapping is used to annotate an action method.

The advantage of annotations is that multiple render and action methods can be defined, and they can be called depending on the request parameters.

The DispatcherPortlet uses a few special infrastructure beans to process requests and render appropriate views; they are implementations of interfaces analogous to MVC servlet interfaces. So when it comes to portlets, handler mappings are used to map requests and portlet modes with controllers, multipart resolvers, and handler exception resolvers. Data binding, command object usage, model handling, and view resolution are the same as in the servlet framework, and they are performed by the same classes. An intermediary servlet bridge class, called ViewRendererServlet, is used for rendering views; it transforms a portlet rendering request to a servlet request and the view can be rendered using the servlet infrastructure specific beans (view resolvers, messageSource, etc.). The only things not available are the usage of the redirect: prefix and RedirectView, because these kinds of operations are linked to the URL of the request, which in this case is generated by the portal and the results would be unexpected.

Most portal applications expect the result of rendering a portlet to be an HTML fragment, so any view technologies like JSP/JSTL, Velocity, FreeMarker, and XSLT are allowed. This also means that Spring taglib and Spring form taglib are supported.

Each portlet has a javax.portlet.PortletMode defined, which indicates the function the portlet is performing in the render method. A portlet can change its portlet mode programmatically when processing an action request. The portlet specification defines three portlet modes: VIEW, EDIT, and HELP. Depending on the security restrictions, a user can have access only to specific portlet modes; unauthenticated users can only use VIEW and HELP, whereas authenticated users can also use EDIT.

Portlets are required to support VIEW mode; and this is the only mode needed—even in complex applications. EDIT and HELP are not mandatory. Portal applications can define their own custom portlet modes. For example, the Liferay Portal has additional portlet modes:

  • ABOUT
  • CONFIG
  • PRINT
  • PREVIEW
  • EDIT_DEFAULTS
  • EDIT_GUEST

Liferay also allows its users to create their own portlet modes.

Spring also acts as a portlet container, providing portlets with a runtime environment and managing their lifecycle. Spring receives requests from the portal and decides which portlet to execute. The portal is responsible with aggregating the resulted content.

The following is the typical flow of events for using a portal application:

  1. The user gets authenticated by the portal.
  2. The user makes an HTTP request to the portal.
  3. The request is received by the portal.
  4. The portal determines if the request contains an action targeted to any of the portlets associated with the portal page.
  5. Using the portlet container, the portal invokes portlets to obtain content to be displayed in the resulting portal page.
  6. The portal aggregates the output of the portlets in the main page, and then sends the results back to the client.

As seen in this example, even if the request is directed to a single portlet in the page, the whole page is being reconstructed and rendered. This can be avoided by using AJAX components in the portlet pages, and instead of action requests, resource requests can be used (methods will be annotated with @ResourceMapping), but this implies adding a lot of resource handling logic for conversion and validation, which otherwise can be done by Spring automatically.

A portal page can be made of one or more portlets, as seen in Figure 4-5.

9781484208090_Fig04-05.jpg

Figure 4-5. Liferay Portal page with various portlet components

Configuration

Spring Portlet is a request-driven web MVC framework designed around the DispatcherPortlet, which is the entry point for a portlet application. It plays the same role as a front controller as DispatcherServlet does for servlet applications. Because each portlet behaves as a stand-alone application, a DispatcherPortlet is defined for each portlet. Each DispatcherPortlet has its own WebApplicationContext, which inherits everything defined in the root WebApplicationContext. Everything inherited can thus be overridden in the portlet-specific scope. A context inheritance diagram example is depicted in Figure 4-6.

9781484208090_Fig04-06.jpg

Figure 4-6. Context inheritance diagram in this chapter’s application sample

Configuring a portlet application can be done by using only XML files, but when working with Spring MVC portlet, it is practical to use annotations to reduce the size of XML configuration files and make them more readable.

In the source code attached to this chapter, two portlets are defined: PortletSearch and PortletAdd. Snippets of code from the content of one or the other are used in this book to provide examples for the terms and definitions being mentioned.

The XML Part of the Configuration

The DispatcherPortlet(s) is/are declared in a configuration file name portlet.xml, which resides under the WEB-INF directory. This file must exist with the mentioned name and in the mentioned location in any web archive containing portlet definitions. It is the configuration file for the portlet applications. You can consider it the equivalent of web.xml for portlets.

A portlet application has the same structure as a normal web application, but the necessary configuration files depend on the portal application. How to use Liferay in this case will be discussed shortly; you can see the application structure provided in Figure 4-7.

9781484208090_Fig04-07.jpg

Figure 4-7. The structure and configuration files for a Liferay portlet application

Each file under WEB-INF has a specific purpose that will be discussed in detail later in this chapter. A short description of these files and their purposes can be seen in Table 4-1.

Table 4-1. Message Converters Table

File Name

Purpose

Observation

app-config.xml

Application configuration

Spring, part of the root context

liferay-display.xml

List of portlets available

Liferay

liferay-portlet.xml

Portlets configuration in the portal

Liferay

mvc-config.xml

Web infrastructure configuration

Spring, part of the root context

personAdd-portlet.xml

PersonAdd portlet configuration file

Spring, inherits root context

personSearch-portlet.xml

PersonSearch portlet configuration file

Spring, inherits root context

The following list describes what every configuration file contains.

  • app-config.xml and mvc-config.xml are the typical Spring configuration files that contain the user-defined application beans and web infrastructure beans that are inherited by portlet contexts:
    <!-- app-config.xml -->
        <context:component-scan base-package="com.pr">
            <context:include-filter type="annotation"
                        expression="o.s.stereotype.Service"/>
            <context:include-filter type="annotation"
                        expression="o.s.stereotype.Repository"/>
        </context:component-scan>

        <!-- Import configuration for the datasource and the dao project -->
        <import resource="classpath:spring/app-dao-config.xml"/>
        <import resource="classpath:spring/db-config.xml"/>

    <!-- mvc-config.xml -->
        <bean id="viewResolver"
              class="o.s.web.servlet.view.InternalResourceViewResolver"
              p:viewClass="org.springframework.web.servlet.view.JstlView"
              p:prefix="/WEB-INF/person/" p:suffix=".jsp"/>

    <bean id="messageSource"
              class="o.s.context.support.ReloadableResourceBundleMessageSource"
              p:basename="classpath:localization/global"
              lazy-init="true"/>
  • liferay-display.xml is a Liferay Portal configuration file, which contains the list of portlets available to add in the pages of a site and a category that groups them together. This file is not mandatory, but it is recommended to create it to shorten the deployment process. Having this file in the war (alongside liferay-display.xml) allows you to install a portlet war application using the App Manager in Liferay, without any additional operations (see Figure 4-8).

    9781484208090_Fig04-08.jpg

    Figure 4-8. The App Manager in Liferay

  • This is the syntax of the file:
    <display>
            <category name="Personal Records">
                  <portlet id="personAdd" />
                  <portlet id="personSearch" />
             </category>
    </display>
  • And when creating a site or a site template, Liferay provides user portlets (see Figure 4-9).

    9781484208090_Fig04-09.jpg

    Figure 4-9. How Liferay provides user portlets for usage in portal pages

  • liferay-portlet.xml is a Liferay configuration file that contains typical settings for user created portlets in the context of the web application: portlet names, if they can be used more than once in a page,4 additional JavaScript files, CSS files,5 and so forth.
    <liferay-portlet-app>
        <portlet>
              <!-- The canonical name of the portlet, it has to be unique -->
              <portlet-name>personSearch</portlet-name>
              <!-- Indicates if multiple instances of this portlet
                   can appear on the same page -->
              <instanceable>false</instanceable>

              <!-- not used in the example, but can appear in a configuration -->
              <footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
              <header-portlet-css>/styles/general.css</header-portlet-css>
              <requires-namespaced-parameters>false</requires-namespaced-parameters>
        ...
           </portlet>
    </liferay-app>

    As these settings are Liferay specific, they won’t be covered in detail here. If you are interested in working with Liferay, you can find more details on the official site at www.liferay.com.

Image !  Starting with Liferay 6.2, the requires-namespaced-parameters parameter must be specified for a portlet. It must be set to false for parameter values to be read correctly. When not specified, the default value is true and the portal associates a unique name to each HTML element in the page to prevent name collisions between different portlets in the page.

  • personSearch-portlet.xml and personAdd-portlet.xml are portlet application configuration files. A configuration file for each portlet must be created. All beans used by the portlet controller bean (except the beans inherited from the root context) are declared in it. The name must match the <portletName>-portlet.xml template, where <portletName> is the name of the portlet as declared in portlet.xml. In our example, only the definition of the portlet controller bean can be specified. This file is loaded by the DispatcherPortlet:
    <bean id="personSearch" class="com.pr.search.PersonController"
          p:personManager-ref="personManager"/>

    But if you want to use annotations as much as possible, you could do so:

    <!-- in personSearch-portlet.xml -->
        <context:component-scan base-package="com.pr.search"/>
        <mvc:annotation-driven/>

    <!-- in personAdd-portlet.xml -->
          <context:component-scan base-package="com.pr.add"/>
          <mvc:annotation-driven/>

    The scanned package contains the portlet controller class and all the components involved in defining the functionality of a portlet. Although the <mvc:annotation-driven/> declaration seems redundant, it is actually needed because portlets are independent applications, even if they inherit the same root context and they reside in the same portal application context.

    As mentioned, each portlet behaves as a standalone application, and that’s why these configuration files are needed. The root Spring configuration is defined in the app-config.xml and mvc-config.xml. Without these configuration files, the deployment will fail, because the Spring MVC portlet expects a configuration file for each portlet. Here is what happens at deploy time if the personSearch-portlet.xml file is missing:

    o.s.w.p.c.XmlPortletApplicationContext - Refreshing PortletApplicationContext
    for namespace 'personSearch-portlet'...
    o.s.b.f.x.XmlBeanDefinitionReader - Loading XML bean definitions from
    PortletContext resource /WEB-INF/personSearch-portlet.xml
    ERROR o.s.w.p.DispatcherPortlet - Context initialization failed
    o.spring.beans.factory.BeanDefinitionStoreException: IOException parsing XML
    document from PortletContext resource /WEB-INF/personSearch-portlet.xml;
    nested exception is java.io.FileNotFoundException:
    Could not open PortletContext resource /WEB-INF/personSearch-portlet.xml
    ...
  • portlet.xml is the configuration file that defines settings for the portlet(s), such as the portlet request handler (the portlet class). When working with Spring only, DispatcherPortlet, supported modes, supported locales, supported MIME types, and the resource bundle are used. This file contains multiple portlet elements—one for each portlet defined in the application.
    <portlet-app ...>
    <portlet>
          <portlet-name>personSearch</portlet-name>
          <portlet-class>o.s.web.portlet.DispatcherPortlet</portlet-class>
                <supports>
                      <mime-type>text/html</mime-type>
                      <portlet-mode>view</portlet-mode>
                </supports>
                <resource-bundle>localization.global</resource-bundle>
                <portlet-info>
                      <title>Person Search</title>
                </portlet-info>
    </portlet>

    <portlet>
         <portlet-name>personAdd</portlet-name>
        ...
        <!-- configuration is analogous to the one for personSearch -->
    </portlet>
    <!-- More settings for other portlets -->
    </portlet-app>
  • web.xml contains the deployment descriptor for the web resources, and this is where the ViewRendererServlet is declared and the connection to the Spring MVC configuration is made. There is no DispatcherServlet defined, because portlet applications run in a portlet context, which is different form a servlet context. According to Portlet Specification 1.0, every portlet application is also a Servlet Specification 2.3–compliant web application, and thus it needs a web application deployment descriptor, meaning a web.xml file:
    <web-app ...>
        <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>/WEB-INF/root-context.xml</param-value>
        </context-param>
        <listener>
            <listener-class>o.s.web.context.ContextLoaderListener</listener-class>
        </listener>

            <servlet>
                    <servlet-name>ViewRendererServlet</servlet-name>
                    <servlet-class>o.s.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>
    </web-app>

The ViewRendererServlet is the bridge servlet for portlet support. During the render phase, DispatcherPortlet wraps PortletRequest into ServletRequest and forwards control to ViewRendererServlet for actual rendering. This process allows the Spring Portlet MVC framework to use the same View infrastructure as that of its servlet version; that is, the Spring Web MVC framework. The /WEB-INF/servlet/view is the default value available for internal resource dispatching. The ViewRendererServlet bridge servlet can be mapped to a different URL pattern by using the viewRendererUrl property.

Image !  As mentioned at the beginning of the chapter, the controllers can be created without annotations by extending the |o.s.web.portlet.mvc.AbstractController class. This is the old way of doing things, before the introduction of the @Controller annotation. It is still supported, but not recommended, and it is not as practical as using an annotated controller. In this case, the <portletName>-portlet.xml looks a little different. The HelloWorldController in the book-code/04-chapter-solution module has a configuration file that looks like this:

<bean id="helloWorldController" class="com.book.HelloWorldController"/>
<bean id="portletModeHandlerMapping"
  class="o.s.web.portlet.handler.PortletModeHandlerMapping">
  <property name="portletModeMap">
       <map>
          <entry key="view">
             <ref bean="helloWorldController"/>
          </entry>
       </map>
  </property>
</bean>

The PortletModeHandlerMapping class is an implementation of the o.s.web.portlet.HandlerMapping interface used by Spring to map from the current PortletMode to request handler beans.

The Annotation Part of the Configuration

At the time this book is being written, a full annotation configuration for a portlet-based application is not possible. A combination of XML and annotations can be used, because Spring MVC annotations are available for usage in portlet controllers too. For example, in the PersonAddController, the @ModelAttribute is used in a similar manner as for a servlet container. The PersonAddController is a simple controller that allows the user to create a person instance.

import org.springframework.stereotype.Controller;

...

@Controller("personAdd")
@RequestMapping("VIEW")
public class PersonAddController {
...
@RenderMapping
    public String render(Model model) {
    model.addAttribute(new Person());
    return "add";
  }

@ModelAttribute
private List<Hospital> getHospitals() {
    return hospitalManager.findAll();
}

@ActionMapping("add")
public void addPerson(@Valid @ModelAttribute Person person,
    BindingResult result, ActionRequest actionRequest,
    ActionResponse actionResponse,
    SessionStatus sessionStatus, Model model) {
    if (!result.hasErrors()) {
        logger.info("ACTION: action saving person = " person);
        try {
              personManager.save(person);
              model.addAttribute("message",
                    messageSource.getMessage("label.Person.saved", null,
                          actionRequest.getLocale()));
              sessionStatus.setComplete();
        } catch (Exception e) {
            logger.error("Unexpected error when saving person.", e);
            model.addAttribute("error", "Internal Error.
                  Contact Administrator.");
        }
    } else {
        logger.info("Validation failed");
        model.addAttribute("errors", result);
    }
  }
}

The model attribute defined by getHospitals() is used to populate the hospital drop-down list in the view fragment in add.jsp. The view fragment is basically normal JSP code; any taglibs can be used, and the portlet taglib is used to define the render and action URLs that will be mapped to methods in the controller responsible for populating and managing data for the JSP fragment.

(1) <%@ taglib prefix="portlet" uri="http://java.sun.com/portlet_2_0"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
(2) <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

(3)<portlet:defineObjects />

<h3>
  <spring:message code="persons.add.title"/>
</h3>

(4)<portlet:actionURL var="addPersonUrl">
   <portlet:param name="javax.portlet.action" value="add"/>
</portlet:actionURL>

(5)<portlet:renderURL var="cleanPersonUrl">
   <portlet:param name="action" value="clean" />
</portlet:renderURL>

<div class="person">
...
<sf:form name="person" modelAttribute="person"
               action="${addPersonUrl}"
               method="POST">
      <table>
          <tr>
             <th>
             <label for="firstName">
                 <span class="man">*</span>
                 <spring:message code="label.Person.firstname"/>
             </label>
           </th>
           <td><sf:input path="firstName"/></td>
           <td><sf:errors cssClass="error" path="firstName"/></td>
         </tr>
         <tr>
             <th>
                <label for="middleName">
                    <spring:message code="label.Person.middlename"/>
                </label>
             </th>
             <td><sf:input path="middleName"/></td>
             <td><sf:errors cssClass="error" path="middleName"/></td>
         </tr>
         ...
         <!-- other form elements -->
         <tr>
             <td>
                  <input type="submit"
                              value=" <spring:message code=’command.save’/>">
             </td>
             <td>
                 <a href="${cleanPersonUrl}">
                     <spring:message code="command.cancel"/>
                 </a>
              </td>
         </tr>
       </table>
     </sf:form>
</div>

The previous sample code is a snippet from the definition of the add.jsp fragment. A few lines are marked with numbers in parentheses; here is why those lines are important:

  • (1) The portlet taglib definition for JRS 286. (A portlet container that supports JSR 286 should also support JSR 168.)
  • (2) The Spring form taglib definition.
  • (3) Needed to use renderRequest, renderResponse, and portletConfig variables.6
  • (4) An element used to define an action URL for a portlet. The javax.portlet.action parameter value must match the value of the @ActionMapping annotation placed on the action method in the controller. Other parameters with different names can be used and the {name,value} pairs, must appear as a value for the @ActionMapping annotation params attribute to correctly identify the action method to use. In the case described in the preceding snippet, the following method will be mapped to the addPersonUrl:
    @Controller("personAdd")
    @RequestMapping("VIEW")
    public class PersonAddController {
    ...
    @ActionMapping("add")
             public void addPerson(...){
            ...
            }
        ...
    }
  • (5) An element used to define a render URL. This element has a parameter, and its name and value appears in the @RenderMapping annotation params attribute to correctly identify the render method to use. In the case described in the preceding snippet, the following methods will be mapped to the cleanPersonUrl:
    @Controller("personAdd")
    @RequestMapping("VIEW")
    public class PersonAddController {
    ...
      @RenderMapping(params = "action=clean")
        public String renderNew(Model model) {
        //the model attribute is removed from the model and a new on is added
        //causing the form to be emptied of data
            model.asMap().remove("o.s.validation.BindingResult.person");
            model.addAttribute(new Person());
            return "add";
        }
    ...
    }

Configuration Details and Recommendations

If you paid enough attention to the example configuration files presented in the previous sections, you might have noticed that there are some common elements between the configuration files; portlet names and portlet ids have to respect some strict rules in order for the portlets to be deployed correctly. Figure 4-10 is a mashup of all files used in defining a portlet. In this image, only configuration elements specific to the PersonAdd portlet are depicted. Analogous elements are also defined for the PersonSearch portlet in this book’s code samples. If you decide to experiment with the provided code and create your own portlet, the configuration should be done similarly to what is presented in Figure 4-10 for the PersonAdd portlet.

When developing a portlet, it is important to keep a standard for naming beans and configuration items; make it as global as possible, because when elements are not found, Spring reports these as errors in the portal application. Spring is quite clear in telling you what is missing, but portal application exceptions can be quite confusing, especially when you are working with a portal application for the first time. So if you want your portlet development to go flawlessly, try to follow these recommendations:

9781484208090_Fig04-10.jpg

Figure 4-10. All the files defining the PersonAdd portlet

  1. Try to start development by writing the controller. Name the controller appropriately. A controller name should be made of the following:
    1. The name of object type being manipulated
    2. The type of manipulation (list, search, edit, add)
    3. The Controller suffix

    For example, a controller that handles requests for searching for a person would be named PersonSearchController. The name of the controller bean should be the object type name + manipulation type. So the PersonSearchController name is annotated with @Controller("personSearch").

  2. The second file is the Spring portlet configuration type. It is named as follows:
    1. The name of the object type being manipulated
    2. The type of manipulation (list, search, edit, add)
    3. The -portlet suffix

    So, a file to configure a portlet that performs a person search would be called personSearch-portlet.xml. Inside this file, a bean defines the controller type that you previously created, and dependencies are injected when XML configuration is used. The bean id is the name of the controller bean defined in the previous step.

    <bean id="personSearch">
          <property name="personManager" ref="personManager"/>
    </bean>

    When annotations are used to configure the necessary components, only the package that you are interested in is scanned, and the <mvc:annotation-driven/> is added:

    <context:component-scan base-package="com.pr.search"/>
    <mvc:annotation-driven/>
  3. The liferay-display.xml is next. Set the portlet id as object type name + manipulation type.
  4. In the liferay-portlet.xml, set the portlet name as object type name + manipulation type too.

    So, for the portlet that displays a list of people, the portlet id and portlet name should be personList.

  5. In portlet.xml, use the same portlet name as you did in the previous step.
  6. Another recommendation is to make portlets that display data instanceable and the portlets that alter data non-instanceable. The reason for this is as follows: if a portlet that displays data is placed twice in the page, both portlets will always display the same data, because they share the request. The same happens with portlets that alter data; so basically, two action requests are made with the same parameters, even if the input parameters have been populated in only one of them. This leads to exceptions at the database level if the database is properly designed. If not, this leads to data duplications, and sometimes data corruption.
  7. If you have only one portlet, the root-context.xml is not necessary and all Spring infrastructure beans can be declared in the <portletName>-portlet.xml.

The Development and Deployment of a Portlet Application

Since this chapter does not cover topics required for the certification exam, no quiz or practical exercises are in it; instead, a short step-by-step tutorial explains how to install, start, and configure Liferay, and deploys the code samples offered to you. After you understand the process and create some portal pages with the given portlets, you can try to create your own portlet by following the recommendations from the previous section.

Download, Install, Start, and Configure Liferay

As mentioned in the beginning of this chapter, Liferay can be downloaded from www.liferay.com/downloads/liferay-portal/available-releases. The following examples use the Community Edition, bundled with Tomcat, because it is free and can be downloaded directly. Also, Tomcat is really easy to use.

After you click the Download button a *.zip file is saved onto your computer. The file is usually named liferay-portal-tomcat-[version]-ce-ga[index]-[date+build_number].zip. Unpack the archive in a desired location. And this is the end of the install process.

If you open the directory, you will see the content depicted in Figure 4-11.

9781484208090_Fig04-11.jpg

Figure 4-11. The Liferay installation archive

The tomcat-[version] is the version of Tomcat that Liferay is based upon. It has the normal structure and functionality of a Tomcat application server, but it contains some extra jars and configuration files for the Liferay Portal application.

Image !  Currently, Liferay is based on Tomcat 7, so a configuration without a web.xml file is not possible.

To start Liferay, you have to open a shell terminal or a Command Prompt instance. Go to the tomcat/bin directory inside the Liferay installation. Start the server as you would start Tomcat.

Windows / Command Prompt
C:{directory}liferay-{version}omcat-{version}in catalina.bat run
# you also have the option to "double-click" on startup.bat

Linux / MacOs shell terminal
cd /{directory}/liferay-{version}/tomcat-{version}/bin ./startup.sh

You can look in tomcat-[version]/logs/catalina.out to see when the server is up and whether exceptions were thrown due to incompatibilities between the Java version and Liferay. There could be other tomcat *.log files in the directory, but the catalina.out file is the one you should be interested in, because it is the main logging file for Tomcat and logs are written into it in real time when the server is up. Liferay 6.2 is compatible with Java 8, however, so no such problem should arise. When the server is started, a window is opened in your default system browser at the address http://localhost:8080.

This page asks you to insert a few settings details. For the examples in this book, the default configuration can be used. The page should look like the one shown in Figure 4-12.

9781484208090_Fig04-12.jpg

Figure 4-12. The Liferay welcome page

Click the Finish Configuration button on the bottom-left corner of the page. The default settings are saved in an internal in-memory database. You should see a confirmation page that looks like the shown one in Figure 4-13.

9781484208090_Fig04-13.jpg

Figure 4-13. Liferay configurations saved confirmation page

Click the Go to my Portal button in the bottom-left corner of the page. The next page is the Terms of Use page. Just scroll down and click the I Agree button. Next, you are presented with a page requiring you to add a password reminder. Just insert something simple and click the Save button. The default password for user [email protected] is test (see Figure 4-14). After introducing a password reminder, you should be redirected to the portal home page (see Figure 4-15). If you see this page, then your server is correctly configured and you can start deploying custom portlets.

9781484208090_Fig04-14.jpg

Figure 4-14. Liferay Password Reminder page

9781484208090_Fig04-15.jpg

Figure 4-15. Liferay Portal home page

In Liferay, portlets have to be added manually to a page by selecting them from a list with available components. A page is usually part of a site. In Liferay, there are also site templates, which can be used to create multiple sites that inherit the configuration of a template. Of course, you could add the portlets directly to the home page you see after logging in, and then start testing them; but for the examples in this chapter, you will use Liferay the proper way.

The first step is to create a site template. To do this, expand the Admin menu and select Control Panel. Figure 4-16 shows where this option is found on the menu.

9781484208090_Fig04-16.jpg

Figure 4-16. Liferay Admin menu

After selecting the Control Panel option, an admin page with all possibilities is displayed (see Figure 4-17).

9781484208090_Fig04-17.jpg

Figure 4-17. Liferay admin page

These options are numbered in Figure 4-17 to show you their order of usage when creating your site:

  1. Link to the Site Templates administration page.
  2. Link to the portlets (Applications) administration page.
  3. Link to the Sites administration page.

This page takes care of administration for the portal application and all sites hosted by it. Sites can be secured or public. They can have users with different access roles and rights. They can have custom pages. Site templates can be created and user-provided portlets can be installed by using the App Manager. So let’s create a public site and populate it with the provided portlet samples.

Click the Site Templates link to display the Site Template configuration page. Click the +Add button. The form for creating the site template is displayed (see Figure 4-18). Insert the name of the site template and a description, if you want (description is not mandatory, the site name is). Click the Save button.

9781484208090_Fig04-18.jpg

Figure 4-18. Liferay create Site Template page

The more extended site template configuration is next. Click the Pages option in the menu on the left. Next, click the Site pages option. In the center of the page, a set of options for all the pages in the site template are presented. One of these options is the theme for all pages. Select the Dark radio button under the Color Schemes section to use the dark scheme for the site template, because in the style sheet used in the example, the style is defined to be compatible with it (see Figure 4-5). Then click the Save button on the right. Figure 4-19 depicts the actual page and the order of operations.

  1. Link to all site pages configurations.
  2. Select the Dark theme option.
  3. Link to the home page template configuration page.
  4. Click the Save button.

    9781484208090_Fig04-19.jpg

    Figure 4-19. Liferay customize site template page

Click the home link (3), to customize the home page. Change the name if you want; in this example, the first letter is in uppercase. Next, select a layout. The preferred layout is 2 Columns (50/50), so the portlets can be added side by side in the page. After doing this, click the Save button. A green message box should appear at the top of the page, letting you know that all went well (see Figure 4-20).

9781484208090_Fig04-20.jpg

Figure 4-20. Liferay customize Home Page Template

So, now a site template has been created; it contains a single page named Home, which is the page the sample portlets implementations will be placed. To do that, you have to preview the site template, which is done by going back to the Site Templates Administration page and clicking the Site Templates button at the top of the page. A list with all the defined site templates is displayed. The last one on the list should be the recently created site template. Click the Actions button for the site and select the View Pages option (see Figure 4-21).

9781484208090_Fig04-21.jpg

Figure 4-21. Liferay Site Templates page

In a new browser window or tab, your site template is opened for customizations. On the left, there is a light-blue button with a + sign on it. If you click it, a menu opens to allow you to modify the content of the home page. Since there is only one page, it is automatically selected. (When there are multiple pages to customize, you would just click a page header to select it, and then all customizations to be done on it.) Click the Applications menu item to see a list of the available out-of-the-box Liferay portlets to add on the page. They are grouped by category. The page in administration mode is shown in Figure 4-22.

9781484208090_Fig04-22.jpg

Figure 4-22. Site Template home page in administration mode

Now it is time to load the sample portlets.

Open the book-code project and run the war task under the 04-chapter-solution project. The execution of this task creates a *.war file under 04-chapter-solutionuildlibs that needs to be deployed to the Liferay Portal. The module contains two portlets:

  • Hello World Portlet is a simple portlet application with a controller created by implementing the o.s.web.portlet.mvc.Controller, as mentioned at the beginning of the chapter. The handleRenderRequest of this portlet sets an attribute to the model, which is displayed during the render phase.
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;

    import o.s.web.portlet.ModelAndView;
    import o.s.web.portlet.mvc.Controller;

    public class HelloWorldController implements Controller {

      public ModelAndView handleRenderRequest(RenderRequest request,
                 RenderResponse response) throws Exception {
           Map<String, Object> model = new HashMap<String, Object>();
           model.put("helloWorldMessage",
                  "Hello World from Spring WEB portlet example application!!");
           return new ModelAndView("helloWorld", model);
    }

      public void handleActionRequest(ActionRequest request,
                      ActionResponse response) throws Exception {
                //we do not have action requests
      }
    }
  • Hello World Portlet2 is a simple portlet application with a controller created and configured using a typical Spring configuration: annotations and XML. As a bonus, this portlet has a @ResourceMapping annotated method that is used to send a text directly to the browser. These types of methods can be used in AJAX calls, as mentioned at the beginning of this chapter.
    import o.s.stereotype.Controller;
    import o.s.ui.Model;
    import o.s.web.bind.annotation.RequestMapping;
    import o.s.web.portlet.bind.annotation.ActionMapping;
    import o.s.web.portlet.bind.annotation.RenderMapping;
    import o.s.web.portlet.bind.annotation.ResourceMapping;
    @Controller("helloworld2")
    @RequestMapping("VIEW")
    public class HelloWorldController2 {

    @RenderMapping
    public String render(Model model){
        model.addAttribute("helloWorldMessage",
              "Hello World from Annotated Spring Portlet!!");
        return "helloWorld2";
    }

    //We do not need to do anything here.
    //Empty method given as example of how action methods are defined.
    @ActionMapping(value="doSomething")
    public void action(ActionRequest request, ActionResponse response){
    }

      //Example of resource request method
      @ResourceMapping(value = "getData")
      public void getData(ResourceRequest resourceRequest,
             ResourceResponse resourceResponse) throws IOException {
           resourceResponse.getWriter().write("Test data for Ajax call.");
      }
    }

Please take the time to analyze the code and the configuration files, and then execute the task and build the *.war. If the task is executed correctly, you should see the result in 04-chapter-solutionuildlibs. Compare Figure 4-23 with your own environment.

9781484208090_Fig04-23.jpg

Figure 4-23. The 04-chapter-solution portlet sample

Now that you have the archive with the portlets, it is time to upload them to Liferay. For this you need to go the portal administration page (Control Panel) and click the App Manager link. A page with all available portlets is displayed.

The following actions must be performed:

  1. Click the Install tab on the menu.
  2. A page with an upload Form will be displayed, asking you to upload an LPKG or a WAR file. Click the Browse button. (On some systems, this button might be named Choose File.)
  3. Select the 04-chapter-solution-1.0-SNAPSHOT.war file.
  4. Click the Install button.

If the *.war file is installed correctly, a green message box appears on the top of the page with the message: The plugin was uploaded successfully and is now being installed (see Figure 4-24).

9781484208090_Fig04-24.jpg

Figure 4-24. Using the App Manager to install custom portlets in Liferay

!  Community editions of Liferay may have minor bugs and throw exceptions, although everything is happening as it should. For example, the Liferay version used to test the portlet implementations, liferay-portal-6.2-ce-ga4, throws a com.liferay.portal.kernel.messaging. MessageListenerException:java.lang.NullPointerException, which is printed in the catalina.out log file, but the portlets are installed correctly.

To make sure that the portlets were installed correctly and are ready to use, click the Manage tab. The 04-chapter-solution-1.0-SNAPSHOT application should be at top of the list because of its name, and if you expand the gray rectangle underneath, you should see something similar to what’s shown in Figure 4-25.

9781484208090_Fig04-25.jpg

Figure 4-25. Correctly installed portlet samples in Liferay

Now is the time to go back to the site template and place these two portlets in the home page. Liferay has a quick navigation menu on top of the page, which can be used for faster navigation between administrative pages. (It is pinpointed to you in Figure 4-25). There is a Sites option on it. By clicking this, the Liferay site–related configurations page is displayed (see Figure 4-21). Now all you have to do is click the Site Templates button, and then preview the site template as shown earlier.

The page shown in Figure 4-22 should have an extra category now, the Chapter 04 Sample. Expand this, and then drag each portlet to the page and place it accordingly. The home page should look like what’s shown in Figure 4-26; you can also see the new category group for the HelloWorld sample portlets.

9781484208090_Fig04-26.jpg

Figure 4-26. Sample portlets added to the page

Before creating a site using the template, the way to uninstall a war application should be presented, because things might go wrong during portlet development. For example, the following exception is thrown at Liferay deployment when the configuration of a portlet application is incorrect:

o.s.w.p.c.XmlPortletApplicationContext - Refreshing PortletApplicationContext
for namespace 'personSearch-portlet'...
o.s.b.f.x.XmlBeanDefinitionReader - Loading XML bean definitions from
PortletContext resource /WEB-INF/personSearch-portlet.xml
ERROR o.s.w.p.DispatcherPortlet - Context initialization failed
o.spring.beans.factory.BeanDefinitionStoreException: IOException parsing XML
document from PortletContext resource /WEB-INF/personSearch-portlet.xml;
nested exception is java.io.FileNotFoundException:
Could not open PortletContext resource /WEB-INF/personSearch-portlet.xml
...

Configuration errors—such as missing beans or missing expected configuration files (like in the preceding exception)—are displayed only in the catalina.out file. In the App Manager you can see the green message confirmation box as long as the file can be read. The difference is message under the portlet name in the Manage section: There are no configurable plugins for this app.

When this happens, click the Manage tab, and then click the Actions button attached to the application you want to uninstall. Select the Uninstall option. See Figure 4-27 for the message and uninstall option.

9781484208090_Fig04-27.jpg

Figure 4-27. Uninstall a portlet application

Now let’s create a site. Select Sites from the top menu, and then select Sites. Click the +Add button. Next, select the Personal Records Template. The succession of these steps is depicted in Figure 4-28.

9781484208090_Fig04-28.jpg

Figure 4-28. The steps to create a site using a site template

You will be directed to a new page, where a name and description can be inserted for the site. There are other options possible, but for now, just accept the default values and click the Save button. The page will look like the one shown in Figure 4-29.

9781484208090_Fig04-29.jpg

Figure 4-29. Site configuration page

After creating the site, more configuration options become available, and you can see them all in the page that is loaded after the save operation. A recommended practice is to customize the site URL, as Liferay will generate one from the site name (which might not be an acceptable URL). For example, for a site named Personal Records Manager, the site URL generated by Liferay is personal-records-manager. To modify a site URL, in the site configuration page, click the Site URL menu option on the right, and then change the generated site URL with the desired URL under the Friendly URL section, as depicted in Figure 4-30.

9781484208090_Fig04-30.jpg

Figure 4-30. Site URL configuration

Click the Save button, and then access the newly created site from the menu. Go to My Sites. The site name should appear in the menu. By clicking it, you should be redirected to the site home page (see Figure 4-31).

9781484208090_Fig04-31.jpg

Figure 4-31. Accessing a Liferay site

After the two extra-simple HelloWorld portlets from the book-code project are added to the site, look in personal-records for the module named 06-pr-mvc-portlet-solution. This module contains two complex portlets: one for creating a Person instance and one for searching the Person database and deleting Person instances. These are complex portlets that access a database and perform actual data modification; they don’t just display data. Most code samples mentioned in this chapter are from these portlets. These portlets have been developed in such a way that all Spring MVC has to offer is included: model attributes, Spring forms, automatic conversion and validation, and so on. The code for the Spring form and validation is the same as the one for forms used in a servlet environment, and you can find it all in Chapter 3. The reason for this is that servlet and portlet environments differ only by the type of requests being resolved and the way they are mapped to handlers. Once a request has been mapped to a handler, processing the data inside the body of a request is independent of the application type.

Please take a look at the project, and then deploy the portlets on Liferay and add them to the site template in the same manner presented so far. Your updated site should afterward look like what is shown in Figure 4-32, or a little different if you chose a different way to place your portlets in the page.

9781484208090_Fig04-32.jpg

Figure 4-32. The Personal Records Manager portal site

Summary

After reading this chapter, you should have a basic understanding of how to use the Spring MVC Portlet framework with the Liferay Portal application. Here is a list of things that you should remember in case you ever end up working on a portal project:

  • Portlets are specialized web components that behave as stand-alone web applications and used to create composite pages in portal applications.
  • The Spring MVC Portlet framework mirrors the Spring MVC framework. The role of the front controller is played by the DispatcherPortlet in portlet applications.
  • A portlet works with two types of requests: render and action. The render requests do not involve business logic or data manipulation; they just request data from the portal to display it in the page. Actions do the actual data manipulation.
  • Most Spring MVC infrastructure beans and features are available for use in portlet applications.
  • Liferay is very compatible with Spring MVC Portlet; the configuration is totally decoupled.

_________________________

1This definition is given in the official Java portlet specification at https://jcp.org/en/jsr/detail?id=286.

2A portlet container is an application that runs portlets and provides the appropriate context. Examples of well-known and widely used portal applications that can be customized using portlets include IBM WebSphere Portal; Liferay Portal, an enterprise web platform for building business solutions; GateIn Portal (formerly JBoss Portal), an open source web site framework; and the Blackboard learning management system.

3Download the Liferay Community Edition from http://www.liferay.com/downloads/liferay-portal/available-releases.

4Portlets behave as stand-alone applications, so it is possible to add the same portlet multiple times to a page, unless configured differently.

5Liferay and other portlet containers provide a context for the portlets to run in. This context contains theme elements defined in CSS files, and additional functionality in the interface via JavaScript. But the user can override or complement Liferay by providing custom CSS and JavaScript files.

6https://blogs.oracle.com/deepakg/entry/jsr286_defineobjects_tag.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.231.194