Portlets are the body and soul of any portal system and Liferay DXP is no different. Without a portlet, custom functionalities cannot be added to any portal. The Liferay portlet enables you to utilize features defined in the portlet specifications, and the cherries on top are the additional features Liferay provides to maximize the utilization of the framework. LiferayMVC is the most implemented portlet type and provides a lot of flexibility to developers. In this chapter, you get some hands-on experience with portlet development basics.
Introduction to Portlets
A portlet is nothing but a web component that is reusable and consists of a view (HTML/JSP page) and a controller (in Liferay, it’s called a controller class). A portlet can also have a model (in the form of classes), which is used when you connect the portlet to a database table. The model, view, and controller working together act as a web component, which can process a login to the controller and model classes and can send information to the portlet’s UI. However, you don’t always need a controller and model in a portlet; a static portlet can also render an HTML/JSP page.
Figure 3-1 shows a sample page where the header and footer of the portal are static, and three portlets are added to the page. This is an example; you can have as many portlets as needed on a single page.
A single portlet can be added more than once; these are called instantiable portlets. Portlets can also communicate with each other. This mechanism is called inter-portlet communication (IPC). The display part of the portlets is highly customizable using CSS, and client-side dynamic functionalities can also be added using JavaScript and jQuery.
To summarize, portlets provide a means of presenting data from one or more sources in a manageable way. A portlet forms a section of the page to be rendered to the end user, making it very useful because several different portlets can be placed on a single page. The end user gets an immersive experience on a single page, whereas it is being rendered separately and from multiple sources.
This section has explained portlet basics; in the next section, you learn about portlet specifications.
Portlet Specifications
Portals and portlets have standards, which essentially define their behavior across all available and upcoming platforms. The first set of standards was introduced in 2003, called the Java Portlet Specification 1.0 or JSR-168. The second set of standards was published in 2008 and was referred to as the Java Portlet Specification 2.0, or JSR-286. The 2.0 specifications were processed on the foundation of JSR-168. JSR-286 ensured backward compatibility while introducing new features, such as inter-portlet communication (IPC), filters and listeners, and more. The latest Java Portlet Specification—3.0 (JSR-362)—was introduced in 2017. It continues the evolution and has added features such as resource dependencies and the Explicit Render state. We do not go into detail about these specifications as they are worthy of a separate book, but if you’re interested, you can read about them on the web in detail.
This section has explained the basics of portlet specifications; in the next section, you learn about the portlet lifecycle.
Portlet Lifecycle
init(): This is the first stage of the portlet lifecycle and is invoked by the portlet container when it is needed to initialize the portlet. The init() method is used for the same. A portlet is initialized only when deployed in the portlet container; the container destroys the existing portlet (if any are available), and then init() is called to initialize it.
render(): Once the portlet is deployed and initialized, it is ready to be added it to the page. When it is added to the page, the default UI of the portlet is rendered for the end user. To render the default view (or any view per se), render() is invoked. Internally, this method will process the configured HTML/JSP and return the HTML content to the portlet for showing the UI to the end user.
processAction: This method is invoked when the Action URL is used in a portlet. As the name suggests, this is used to process any action for the end user, such as clicking a button or hyperlink, and generally, these actions are CRUD operations.
processEvent(): This method was introduced in the Portlet Specifications 2.0 (JSR 286). This is mainly used for inter-portlet communication, also introduced in the same JSR 286 standards. This method is invoked on an event raised by another portlet. You learn more about IPC in a later part of the book.
serveResource(): This method was also introduced in the Portlet Specifications 2.0 (JSR 286) and is used for AJAX request handling. It is invoked when a Liferay resource URL is processed.
destroy(): This is the last method of a portlet lifecycle and is executed when the portlet is undeployed from the portlet container. This method ensures that the portlet is removed from the portlet container and is no longer available on the portal so cannot be added to the page.
This section has explained the portlet lifecycle; in the next section, you learn about portlet modes and window states.
Portlet Modes and Window States
Another difference portlets have from servlets is portlet modes, which are distinct modes and window states.
Portlet Mode
View mode: This is the default mode of any portlet and is the most commonly used mode. This mode is used to access the portlet’s default/main functionality.
Edit mode: This is a portlet’s configuration mode used to customize the portlet's default view or behavior. You can use this mode when you want to let users perform actions in Edit mode so that customization can be done.
Help mode: This mode provides helpful information to the end users.
Liferay DXP also has a few additional window states—About, Config, Edit Default, Edit Guest, Print, and Preview Mode.
Window States
Normal Window State: This is the default window state of a portlet and allows a portlet to be present with other visible portlets on the same page.
Maximized Window State: This window state is rendered; when it expands on a complete page of the portal, other portlets are not rendered, and only the portlet in a maximized window state is visible on the entire page.
Minimized Window State: This allows only the title bar of the portlet to be visible on the page.
This section has explained portlet modes and window states; in the next section, you learn the basics of Java standard portlets.
Java Standard Portlets
Annotation: @ProcessAction, @ProcessEvent, and @RenderMode
Methods to override: processAction, doView, doEdit, doHelp, init, and destroy
HelloApressPortlet Class Extending GenericPortlet
In this example, if you observed the render method, you created an ActionURL using the createActionURL method. These URLs are called portlet URLs. In the example, a portlet URL will reference the instance of the portlet in the portal page. (There will be different PortletURLs even if the same portlet class is being used in more than one portlet.)
createActionURL: This method creates the action URL for forms or links that will be used to process the actions on the portlets.
createRenderURL: This method creates the render URLs for tasks that don't contain the portlet’s state modifications.
A Closer Look at HelloApressPortlet
RenderRequest: Represents the request sent to the portlet to handle a render. The RenderRequest object is created by the portlet container and then is handed over to the portlet’s render() method as an argument.
RenderResponse: Defines an object to assist a portlet in sending a response to the portal. The RenderResponse object is created by the portlet container and then handed over to the portlet’s render() method as an argument.
ActionRequest: Represents the request sent to the portlet to handle an action. The ActionRequest object is created by the portlet container and then handed over to the portlet’s processAction() method as an argument.
ActionResponse: Represents the response for an action request. The ActionResponse object is created by the portlet container and then handed over to the portlet’s processAction() method as an argument.
EventRequest: Represents the request sent to the portlet to handle an event. It extends the PortletRequest interface to provide event request information to portlets.
EventResponse: Represents the portlet response to an event request.
javax.portlet.title: The title should be displayed in the title bar of this portlet. Only one title per locale is allowed. Note that this title may be overridden by the portal or programmatically by the portlet.
javax.portlet.short-title: A short version of the title that may be used for devices with limited display capabilities. Only one short title per locale is permitted.
javax.portlet.keywords: Keywords describing the functionality of the portlet. Portals that allow users to search for portlets based on keywords may use these keywords. Multiple keywords per locale are permitted, but must be separated by commas.
javax.portlet.description: Description of the portlet.
javax.portlet.display-name: Name under which this portlet is displayed, deployment time or to tools. The display name need not be unique.
javax.portlet.app.custom-portletmode.<,name>.decoration-name: Decoration name for the portlet managed custom portlet mode.
This section has explained the basics of Java standard portlets; in the next section, you learn about the Liferay portlet module.
Liferay Portlet Module (MVC Portlet)
Model View Controller (MVC) patterns are one of the most common patterns for developing Web applications worldwide. The Liferay MVC portlet is an implementation for developing Liferay DXP portlets. You should have an idea about how MVC works in a portlet, which was explained at the beginning of this chapter.
Liferay MVC has benefits compared to the standard MVC pattern, the greatest of which is that it’s lightweight, being an extension of GenericPortlet. It minimizes the effort of maintaining separate configuration files. In addition, it provides an empty portlet file and folder structure, saving effort in writing initialization code with predefined parameters as part of the boilerplate. You can also break down the controller class into separate commands depending on the phases. It abstracts a lot of complexity of portlet development and makes it easier for developers to implement features and operations.
Model: This layer holds the application data and logic for manipulation.
View: This layer displays the data.
Controller: This layer acts as a middleman in the MVC pattern. It passes the data between the View and Model layers.
API: These modules define the interfaces.
Implementation: These modules provide concrete classes that implement interfaces.
Client: These modules consume the APIs.
Now you see how to create an example Liferay MVC portlet to better understand the Liferay MVC portlets.
Creating a Sample Liferay MVC Portlet
- 1.
Liferay workspace: Open your Liferay Developer Studio with a Liferay workspace. This example uses apress_ws as a Liferay DXP workspace. This workspace contains all the code from this book.
- 2.
Template selection: Right-click the Liferay workspace as shown in Figure 3-4 and select Liferay Module Project as the module template.
- 3.
Create a Liferay module project: After selecting a module template, you need to provide a project name. Name it apressMVC and then select Gradle for the build type and mvc-portlet for the project template name, as shown in Figure 3-5.
- 4.
Create a portlet: Now, you need to provide your class name and package, or it will create one by default. Once you’re done, click the Finish button. This example uses ApressMVC for the controller name and com.apress.handsonliferay for the package name, as shown in Figure 3-6.
- 5.
ApressMVC portlet: Once you click the Finish button, it will generate all required files for the Liferay MVC portlet with the default content from the template you selected.
- 6.
Portlet path: This path will be created inside the modules folder of your workspace.
- 7.
Portlet building: As shown in Figure 3-7, you can see the Gradle Tasks window in the Liferay Developer Studio, which will help build the Liferay MVC portlet. Click the Build task by choosing Gradle Tasks ➤ apress_ws ➤ Modules ➤ apressMVC ➤ Build ➤ Build, as shown in Figure 3-7. This will build your Gradle module.
- 8.
Jar creation: Once you click the Deploy task from Gradle Tasks ➤ apress_ws ➤ Modules ➤ apressMVC ➤ Build ➤ Deploy, it will generate the JAR file and store it in the workspace directory location apress_ws ➤ bundles ➤ osgi ➤ modules ➤ *.jar.
- 9.
Portlet deployment: You can copy this JAR file manually to the following server location to deploy the ApressMVC portlet in the Liferay Server: Liferay server folder ➤ deploy folder. For example:
- 10.Successful deployment: You’ll see the following message on the Liferay Server Console once you deploy the module.2022-04-18 11:51:25.495 INFO [fileinstall-directory-watcher][BundleStartStopLogger:46] STARTED com.apress.handsonliferay_1.0.0 [1535]
- 11.
Portlet view: Once you add the ApressMVC portlet to your page, you’ll see the output in Figure 3-8.
Understanding the Liferay MVC Portlet Controller
In this section, you learn more about the Liferay MVC portlet controller, which will be available for every MVC portlet. Let’s look at the controller you created in the earlier example.
All portlet customizations will be discussed based on the ApressMVC portlet created in the previous section.
ApressMVCPortlet extends Liferay’s MVCPortlet class from com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet, which will help this class become the controller for the MVC pattern. In this controller, the most important section is @Component.
Component Section in Controller
immediate = true declares this component and it must be immediately activated or should be delayed.
property = { defines the properties for this component.
com.liferay.portlet.display-category=category.sample is the category to show the portlet
com.liferay.portlet.header-portlet-css=/css/main.css is the path of the CSS files
com.liferay.portlet.instanceable=true is the instanceable configuration
javax.portlet.display-name=ApressMVC displays the name of the portlet
javax.portlet.init-param.template-path=/ is the template path
javax.portlet.init-param.view-template=/view.jsp is the path for the View modules
javax.portlet.name=" + ApressMVCPortletKeys.APRESSMVC is the portlet name
javax.portlet.resource-bundle=content.Language is the locale configuration
javax.portlet.security-role-ref=power-user,user contains the roles for the portlet
service = defines the types under which to register this component as a service.
Understanding the Different URLs in the Liferay MVC Portlet
Render URL
Action URL
Resource URL
Each URL has its own features; let’s discuss them in detail.
Render URL
In the ApressMVC portlet, by default, two JSPs (init.jsp and view.jsp) are created while creating the ApressMVC portlet; you will create one more JSP called renderexample.jsp to perform navigation in the same path.
- 1.
The init.jsp page is created by default. The MVC portlet template will have all tag libraries declared that are required for the Liferay MVC portlet, as shown in Listing 3-3.
apressMVC Portlet init.jsp
- 2.
The view.jsp page is created by default by the MVC portlet template and it includes init.jsp to include the tag libraries. You wrote the logic for creating a Render URL, which will redirect to the render example JSP page using the following tag (see Listing 3-4).
JSP Code Snippet for Render URL
apressMVC Portlet renderexample.jsp
- 4.
The ApressMVCPortlet.java class acts as a controller, created by the default MVC portlet template. In the controller class, you will write the logic in Listing 3-6 for rendering. The render method will be overridden to use the path you click.
apressMVC Portlet Controller with Render Method
This example will help you navigate between Screen1 and Screen2 with the help of the Liferay MVC Portlet Render URL.
Action URL
This URL binds your portlets’ action-handling methods to frontend/UI components using the portlet action URL. The following example helps elucidate the Action URL created in the ApressMVC portlet.
- 1.
In the view.jsp file, you create the Action URLs in different ways available in Liferay MVC portlet, and these URL-related methods will be created in the controller of the ApressMVC portlet. The <portlet:actionURL> tag creates a URL, as shown in Listing 3-7.
JSP Code Snippet for Action URL
- 2.
In the ApressMVCPortlet.java controller class, you write the following logic for all action methods that are created in the view.jsp file.To execute the action method, the name parameter value of <portlet:actionURL> in the JSP page and the action method name in ApressMVCPortlet should be the same, as shown here:
apressMVC Portlet Controller Code Snippet for Action Method
- 3.Once you deploy the ApressMVC portlet, you will see the screen in Figure 3-13 as output. If you click any action URL that you created in JSP, you’ll see a message in the Liferay Server Console.
Resource URL
This URL performs tasks without refreshing your page. The best example for this URL is the auto-complete feature in Google search (it will fetch the matching result while typing itself). The following example explains the ResourceURL, created in the ApressMVC portlet. In this example, try downloading a sample file called apressMVCResource.csv using the Resource function.
- 1.
In the View.jsp page, you are creating the ResourceURL to call the Resource method of the controller. <portlet:ResourceURL> creates the resource URL, which calls the serveResource method of the controller. Listing 3-9 illustrates this process.
JSP Code Snippet for the Resource URL
- 2.
In the ApressMVCPortlet.java controller, you are overriding the serveResource method to write the logic to download a file called apressMVCResource.csv at every click of the ResourceURL from the JSP page. See Listing 3-10.
apressMVC Portlet Controller Code Snippet for Resource Method
Understanding Different Commands in the Liferay MVC Portlet
MVC Render command
MVC Action command
MVC Resource command
Each command has its own features; let’s discuss each MVC command in detail.
The MVC Render Command
These classes handle which page to render, similar to other render methods. They are invoked by the MVCPortlet render URLs. If you want to build simple logic, you can implement all of it in your portlet class. If you want to build complex logic, use the MVC Render commands. The following examples illustrate this concept. You’ll be adding them to the ApressMVC portlet.
- 1.
In the View.jsp page, you create the RenderURL to call the MVC Render command Class. The following tag is used to achieve that:
JSP Code Snippet with Render Command URL
- 2.
The apressmvcrendercommand.jsp file redirects from the MVC Render Command Class’s render method whenever you click Go to Render Command Page from view.jsp. This JSP is created in the same path as view.jsp.
- 3.
The ApressMVCRenderCommand.java class implements the logic for the MVC Render command. It will implement the MVCRenderCommand interface (com.liferay.portal.kernel.portlet.bridges.mvc.MVCRenderCommand) to achieve the MVC Render command features. This class is created in the path of ApressMVCPortlet.java. The following points are mandatory while implementing and will come in the Component section.
service = MVCRenderCommand.class: The Component section
"Javax.portlet.name=" + apressmvcportletkeys.APRESSMVC: The portlet name must be the same for your Render command class and MVC controller.
mvc.command.name=/apressmvcrendercommand: This property value should be the same as your JSP <portlet:param name="mvcRenderCommandName" value="/apressmvcrendercommand" />.
ApressMVCRenderCommand Class for the Render Command URL
MVC Action Command
This command handles actions as separate classes. With the help of Action commands, you can organize action logic in MVCPortlet that has many actions. These action URLs in the portlet’s JSPs invoke a designated MVC Action command class. This section discusses in detail the MVC Action commands with an example.
- 1.
In the View.jsp page, you create the Action URL to call the MVC Action command class by using the following tag:
JSP Code Snippet with ActionCommand URL
- 2.
The ApressMVCActionCommand.java class implements the logic for the MVC Action command to execute the action methods. It will implement the MVCActionCommand interface, and this class is created in the ApressMVCPortlet.java path. The following points are mandatory while implementing and will be in the Component section.
The portlet name must be the same as your Action Command class and MVC Controller.
ApressMVCActionCommand Class for Action Command URL
- 3.
Figure 3-17 displays what you see after deploying the ApressMVC portlet. If you click the Go to Action command class, it will show the “Invoking Action Command Method” message in your Liferay Console.
MVC Resource Command
MVC Resource Command classes fetch resources such as XML, documents, images, or any other resources from a DXP/portal instance without triggering actions or renders. Requests or portlet resource URLs invoke MVC Resource commands. This section discusses in detail the MVC Resource commands with an example.
- 1.
In the View.jsp page, you create the ResourceURL to call the MVC Resource command class.
JSP Code Snippet with Resource Command URL
- 2.
The ApressMVCResourceCommand.java class implements the logic for the MVC Resource command to execute the file download. It will implement the MVCResourceCommand interface, and this class is created in the ApressMVCPortlet.java path. The following points are mandatory while implementing and will come in the Component section.
The portlet name must be the same as your resource command class and MVC controller.
mvc.command.name=/apressmvcresourcecommand command name from the resource command class must match the resourceURL param of JSP <portlet:actionURL name="/apressmvcresourcecommand" />
ApressMVCResourceCommand with MVC Resource Command Code Snippet
- 3.
If you click the Resource command URL to download a file after deploying the ApressMVC portlet, it will download a file called apressMVCResourceCommandFile.csv, as shown in Figure 3-18.
Implementing Window State
You have already read about the Window state in a previous section of this chapter. You will now try to implement it in your ApressMVC portlet by following these steps.
- 1.
In the View.jsp page, you are creating the all window state URLs to execute; see Listing 3-17.
JSP Code Snippet for Window Modes
- 2.
Figure 3-19 shows the output screen that will display after you deploy the ApressMVC portlet with window states to the Liferay Server.
After every click, it will perform some actions.
This section has explained the Liferay portlet module; in the next section, you are introduced to other portlet modules that can be created in Liferay DXP.
Introduction to Other Portlet Modules
The Spring MVC Portlet
The next most popular portlet type in portlet development is the Spring MVC portlet. Liferay allows you to create/deploy portlets with the Spring framework. Liferay provides development standards, and any module that follows the standard is deployable in Liferay. This does not mean that other Liferay features, such as service builder, externalization, and so on, become useless if you are not using the Liferay MVC portlet. They are also usable in the Spring MVC portlet because it is essentially just a change in the application layer. PortletMVC4Spring is a way to develop portlets using the Spring Framework and the Model View Controller (MVC) pattern.
A significant difference between the Liferay MVC Portlet and the Spring MVC Portlet is that, when built for deployment, a Spring MVC module generates a WAR file instead of a JAR file. This is because it has become a Java EE-style web application. Thanks to Liferay for using OSGi WAB standards (Web Application Bundler) for deployment, you can deploy this WAR on the Liferay Server.
Liferay Soy Portlet
Liferay Soy portlet is essentially a Liferay MVC portlet with the added functionality of using Soy templates. Soy templates make it easy to create complex frontends.
JSF Portlet
Liferay provides support for JavaServer Faces standards. This is made possible with the help of the Liferay Faces Bridge. Liferay has created a separate project for supporting JSF named Liferay Faces. This Liferay Faces Bridge allows for the deployment of JSF applications, and the most significant advantage is that you need not write custom Java code. This is made possible with the support of JSF 2.0 standards within Liferay DXP. Other portlets supported by Liferay faces include Liferay Faces Alloy and Liferay Faces Portal.
Bean Portlet
Contexts and Dependency Injection (CDI) is part of the Portlet Specification 3.0, and Liferay supports this with the help of the Bean portlet. The Bean portlet allows custom CDI such as @PortletSessionScoped, @PortletRequestScoped, and @RenderStateScoped. CDI enables portlet classes instantiated via a CDI container, enabling dependency injection along with scope annotations of the portlet classes. Bean portlets are essentially just plain old Java objects (POJOs); descriptors mark them as portlets.
This section introduced different types of portlets; in the next section, you see the Gogo shell in action.
Gogo Shell in Action
From the explanation and example in the previous chapter, you know what the Gogo shell is and what it is capable of. Now you learn how you can use it in detail. Follows these steps to use the Gogo shell in Telnet.
If you are using the Windows operating system, the Telnet feature is enabled in the Add/Remove programs section.
If you are using Linux, Telnet should be installed.
Gogo Shell from the Liferay Control Panel
To access the Gogo shell from the control panel, choose Control Panel ➤ System ➤ Gogo Shell (see Figure 3-25).
Gogo Shell from the Blade CLI
Summary
Liferay DXP portlets enable you to utilize all the features defined in the portlet specifications. The cherries on top are the additional features Liferay provides to maximize the utilization of the framework. Obviously, because the additional Liferay features are Liferay specific, not generic, these portlets cannot be used on any other portlet containers. It does not mean that these additional features do not follow the portlet standards; Liferay has added features such as APIs to improve development with less effort. You learned about these additional portlet modes in this chapter. Another example is the MVC Portlet implementing standard called MVC Pattern, which simplifies portlet development. Generic portlets are also easily deployable on the Liferay DXP portal.
In the next chapter, you learn about a few advanced Liferay concepts.