JavaBeat

  • Home
  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)
  • Privacy
  • Contact Us

PortletSession-based Inter-Portlet Communication

April 30, 2011 by Krishna Srinivasan Leave a Comment

This article is based on Portlets in Action, to be published June 2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) ebooks and pbooks. MEAPs are sold exclusively through Manning.com. All print book purchases include an ebook free of charge. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information.

also read:

  • Java Tutorials
  • Java EE Tutorials
  • Design Patterns Tutorials
  • Java File IO Tutorials

Inter-Portlet Communication

Introduction

Inter-portlet communication using PortletSession is one of the most widely used techniques since Portlet 1.0. Data stored in APPLICATION_SCOPE of PortletSession can be shared with servlets/portlets that form part of the same portlet application.

Say, we had a book catalog portlet. Because all portlets belonging to a portlet application are defined in the same portlet deployment descriptor, the first thing we need to do is define Book Catalog and Recently Added Book portlets in the same portlet.xml file. portlets belonging to a portlet application must be packaged in the same WAR file; therefore, we must create a single WAR containing the Book Catalog and Recently Added Book portlets.

CODE REFERENCE

I recommend that you import ch11_ipc_session eclipse project from the source code that accompanies portlets in Action to view the code listings presented in this section.

Defining multiple portlets in portlet deployment descriptor

You can define multiple portlets in portlet.xml by adding a <portlet> element for each portlet that belongs to the portlet application. Listing 1 shows a portlet.xml file that defines the Book Catalog and Recently Added Book portlets.

Listing 1 Portlet deployment descriptor—multiple portlets

[code lang=”xml”]&lt;portlet-app….&gt;
&lt;portlet&gt;
&lt;portlet-name&gt;recentBook&lt;/portlet-name&gt; #1
&lt;portlet-class&gt; #2
chapter11.code.listing.base. #2
[CA]RecentlyAddedBookPortlet #2
&lt;/portlet-class&gt; #2
&lt;expiration-cache&gt;0&lt;/expiration-cache&gt; #3
&lt;cache-scope&gt;private&lt;/cache-scope&gt;
&lt;resource-bundle&gt; #4
content.Language-ext #4
&lt;/resource-bundle&gt; #4
&lt;portlet-info&gt;
&lt;title&gt;Recently Added Book&lt;/title&gt;
&lt;/portlet-info&gt;
&lt;/portlet&gt;
&lt;portlet&gt;
&lt;portlet-name&gt;bookCatalog&lt;/portlet-name&gt; #5
&lt;portlet-class&gt; #6
chapter11.code.listing.base.BookCatalogPortlet #6
&lt;/portlet-class&gt; #6
….
&lt;expiration-cache&gt;60&lt;/expiration-cache&gt;
&lt;cache-scope&gt;private&lt;/cache-scope&gt;
….
&lt;resource-bundle&gt; #7
content.Language-ext #7
&lt;/resource-bundle&gt; #7
&lt;portlet-info&gt;
&lt;title&gt;Book Catalog&lt;/title&gt;
&lt;/portlet-info&gt;
….
&lt;/portlet&gt;
….
&lt;/portlet-app&gt;

#1 Name of Recently Added Book portlet
#2 Portlet class
#3 Expiration cache set to 0
#4 Resource bundle for the portlet
#5 Name of Book Catalog portlet
#6 Portlet class
#7 Resource bundle for the portlet[/code]

At #1, the name of the Recently Added Book portlet is defined. At #2, the fully qualified class name of the Recently Added Book portlet is specified. At #3, <expiration-cache> specifies the expiration timestamp for the cached content as 0, which means that the content generated by the Recently Added Book portlet is always considered expired by the portlet container. At #4, the <resource-bundle> element defines the resource bundle used by the Recently Added Book portlet. At #5, the name of the Book Catalog portlet is defined. At #6, the fully qualified class name of the Book Catalog portlet is specified. At #7, the resource bundle used by the Book Catalog portlet is specified.

NOTE

Listing 1 shows that the Book Catalog and Recently Added Book portlets use the same resource bundle for labels/messages, which is not unusual.

In a portlet deployment descriptor, each <portlet> element contains configuration information specific to the portlet. The configuration information specified as the sub-element of the <portlet-app> element applies to the portlet application, that is, to all portlets that form part of the portlet application. For instance, the <container-runtime-option> sub-element of the <portlet-app> element applies to all portlets defined in the portlet deployment descriptor.

NOTE

portlets packaged in the same portlet application are usually closely related to each other in their functionality and mostly share a common code base.

Now that we have defined portlets in portlet.xml file, let’s look at how the Book Catalog portlet communicates with the Recently Added Book portlet using PortletSession.

Storing and receiving information from PortletSession

When a user adds a new book using the Book Catalog portlet, the Recently Added Book portlet is supposed to display the information about the newly added book. As the Recently Added Book portlet is not the target of user action, the Book Catalog portlet is responsible for communicating to the Recently Added Book portlet that a new book has been added and that it needs to regenerate its content to reflect the newly added book.

What information to communicate

We know how to pass information from the Book Catalog to the Recently Added Book portlet (which is by using PortletSession) but we don’t know what information we should pass. While developing portlets, you need to carefully choose what information you want to pass because that will affect the content generation logic of the target portlet.

NOTE

In the context of inter-portlet communication, we’ll use the term sender portlet to refer to the portlet responsible for initiating communication and receiver portlet to refer to the portlet, which is at the receiving end of the communication. Sender portlet(s) are the target of user actions and receiver portlet(s) are portlets that should update their content based on the action taken by the user on the sender portlet(s). For instance, in our sample scenario, the Book Catalog is the sender portlet and the Recently Added Book is the receiver portlet. In some inter-portlet communication scenarios, the sender may also act as the receiver and vice versa.

Let’s look at possible candidate information that can be sent to the Recently Added Book portlet:

  • Complete information about the newly added book—the portlet doesn’t need to hit the catalog data store as the complete information is available in PortletSession.
  • The newly added book’s ISBN number—the portlet will retrieve the book’s details from the catalog using the ISBN number available in PortletSession.
  • A flag indicating that a new book was added to the catalog—the portlet uses this flag as an indicator that it needs to re-execute the logic to find the recently added book. In this case, the portlet will hit the catalog data store to find the newly added book.

You can send any of these pieces of information to the Recently Added Book portlet, but there are trade-offs for each choice. If you send complete information via PortletSession, you are overloading your session. If you are only sending the ISBN number, you get a performance trade-off because the portlet will have to make a round-trip to the catalog data store.

From the receiver portlet’s perspective, the communicated information can be classified as shown in table 1.

In most scenarios, the partial information approach is used because the receiver portlet usually needs to process the communicated information to generate its content.

TIP

You should avoid putting information in PortletSession during the render phase. When an action method is invoked in response to a user action on the sender portlet, you should only set the session attributes. The sequence of the render method invocations for portlets in a portal page is undefined. Therefore, if you put information in PortletSession in the render method, the other portlet(s) may not be able to read it because their render methods were already invoked by the time the information was put in PortletSession.

In inter-portlet communication scenarios, it is equally important to consider situations in which the communicated information is not available or was not delivered to the receiver portlet—the No information case defined earlier. The receiver portlet should show meaningful content even if the communicated information hasn’t been delivered or is unavailable. For instance, if the Recently Added Book portlet is completely dependent on the ISBN number stored in PortletSession for generating its content, it will not show any book details until the user adds a new book to the catalog. This gives the impression that no book has ever been added to the catalog and the catalog should be empty.

NOTE

Because we are not using a database for the examples in this article, the Book Catalog is stored as a ServletContext attribute named bookCatalog by BookCatalogContextListener (a servlet context listener). Refer to the web.xml file and the BookCatalogContextListener class in ch11_ipc_session source folder that accompanies Portlets in Action.

Caching and inter-portlet communication

In inter-portlet communication scenarios, content caching in the receiver portlet can be a spoilsport. This is how: if the receiver portlet caches the content based on the expiration-based or validation-based caching strategy, the content of the receiver portlet is not updated until the content expires or becomes invalid. So, even if you pass information via PortletSession to the receiver portlet, it will not result in updated portlet content until the cached content expires and the receiver portlet’s render method is invoked.

In our sample inter-portlet communication scenario, the Book Catalog portlet communicates the ISBN number of the newly added book to the Recently Added Book portlet via PortletSession. The content generation logic of the Recently Added Book portlet is responsible for showing meaningful content if the ISBN number of the newly added book is not available in PortletSession.

Listing 2 shows the addBook method of the BookCatalogPortlet class, which adds the ISBN number of the newly added book to PortletSession.

Listing 2 BookCatalogPortlet class—addBook method

[code lang=”java”]@ProcessAction(name = &quot;addBookAction&quot;)
public void addBook(ActionRequest request, #1
ActionResponse response)throws…. { #1
….
if (errorMap.isEmpty()) { #2
bookService.addBook(new Book(category, name, #3
author, Long.valueOf(isbnNumber))); #3
request.getPortletSession().setAttribute #4
(&quot;recentBookIsbn&quot;, isbnNumber, #4
PortletSession.APPLICATION_SCOPE); #4
….
}
}[/code]

At #1, the addBook method of the BookCatalogPortlet class is responsible for adding a book to the catalog. At #2, the addBook method checks if errorMap is empty. errorMap is a HashMap, which contains validation errors occurred during the validation of the user-defined book information. If errorMap is empty (that is, no validation errors occurred), the book information is saved in the catalog by calling the addBook method of BookService, at #3. At #4, the ISBN number of the newly added book is set in the APPLICATION_SCOPE of PortletSession with name recentBookIsbn.

The ISBN number information stored in the PortletSession is now accessible to Recently Added Book portlet. Listing 3 below shows how the RecentlyAddedBookPortlet class retrieves the ISBN number from PortletSession and uses it to generate its content. If the ISBN number is found in the session, then it sorts books available in the catalog to find the recently added book.

Listing 3 RecentlyAddedBookPortlet class

[code lang=”java”]public class RecentlyAddedBookPortlet extends GenericPortlet {
@RenderMode(name=&quot;view&quot;)
public void showRecentBook(RenderRequest request, #1
RenderResponse response)throws ….{ #1
String isbnNumber = (String)request. #2
getPortletSession().getAttribute(&quot;recentBookIsbn&quot;, #2
PortletSession.APPLICATION_SCOPE); #2
….
if(isbnNumber != null) {
if(bookService.isRecentBook
(Long.valueOf(isbnNumber))) {
book = bookService.getBook(Long. #3
valueOf(isbnNumber)); #3
} else {
book = bookService.getRecentBook(); #4
}
} else {
book = bookService.getRecentBook(); #5
}
request.setAttribute(&quot;book&quot;, book); #6
getPortletContext().getRequestDispatcher( #7
response.encodeURL(Constants.PATH_TO_JSP_PAGE + #7
&quot;recentPortletHome.jsp&quot;)).include(….); #7
}
}

#1 Render method for VIEW mode
#2 Retrieve ISBN number from PortletSession
#3 Retrieve book details using ISBN number
#4 Retrieve recent book from catalog
#5 Retrieve recent book from catalog
#6 Generate portlet content using JSP page[/code]

At #1, showRecentBook defines the render method for the VIEW portlet mode. At #2, showRecentBook method retrieves the recentBookIsbn session attribute from APPLICATION_SCOPE. The recentBookIsbn attribute contains the ISBN number of the recently added book set by the Book Catalog portlet (refer to listing 2). At #3, if the ISBN number stored in the recentBookIsbn session attribute represents a recently added book in the catalog, the getBook method of BookService is called to obtain the details of the book whose ISBN number matches the value of the recentBookIsbn session attribute. At #4, if the ISBN number stored in the recentBookIsbn session attribute doesn’t represent a recently added book in the catalog, getRecentBook method of BookService is used to retrieve the recently added book from the catalog. At #5, if the recentBookIsbn session attribute is not found, the getRecentBook method of BookService is used to retrieve the recently added book from the catalog. At #6, the Book object returned by the getBook/getRecentBook method is set as a request attribute for use by the JSP page responsible for rendering content. At #7, a request is dispatched to the recentPortletHome.jsp page of the Recently Added Book portlet to show the details of the recently added book.

Listing 3 shows that the RecentlyAddedBookPortlet class does a lot of work to ensure that the content is meaningful in the context of user action. For instance, if it doesn’t find the recentBookIsbn session attribute or if it finds the ISBN number referenced by the recentBookIsbn session attribute doesn’t represent a recent book in the catalog then it executes a complex logic within the getRecentBook method to fetch the newly added book.

CODE REFERENCE

The getRecentBook method of BookService is responsible for fetching fresh catalog data and sorting it based on a sequence number assigned to each book in the catalog. The book with the highest sequence number is considered as the recently added book in the catalog.

We’ve just seen in listings 2 and 3 how PortletSession is used by the Book Catalog and Recently Added Book portlets to implement inter-portlet communication. Pretty neat, huh? Now we are ready to look at how to build, deploy, and test inter-portlet communication between the Book Catalog and Recently Added Book portlets.

Inter-portlet communication in action

Earlier we saw how to write portlets that communicate using PortletSession. Now, we’ll see how our Book Catalog and Recently Added Book portlets communicate when deployed in a web portal.

Let’s look at the steps that we need to take to test communication between our sample portlets.

Build and deploy portlet application WAR file

The steps to build and deploy portlet application containing multiple portlets are the same as for the portlet application containing a single portlet.

Create portal pages

Because we want to test inter-portlet communication in situations when communicating portlets are located on different portal pages, you should create two portal pages named Book Catalog and Recent Book.

Communicating portlets on the same portal page

To test inter-portlet communication, add the Book Catalog and Recently Added Book portlets to the Book Catalog portal page, as shown in figure 1.

Figure 1 shows communicating portlets on the same portal page. To test the communication between the sample portlets, add a new book to the catalog. You’ll discover that the Recently Added Book portlet updates its content to reflect the new book.

Communicating portlets on different portal pages

To test the communication between the sample portlets when they are located on different portal pages, add the Book Catalog portlet to the Book Catalog portal page and the Recently Added Book portlet to Recent Book. Now, add a new book to the catalog and check if the Recently Added Book portlet content reflects the details of the newly added book. You’ll find that the Recently Added Book portlet does show information about the newly added book.

So, now you’ve seen just how easy it is to get your portlets talking to each other, whether they’re on the same portal page or different ones. Next, we’ll take a look at the pros and cons of using PortletSession for inter-portlet communication.

Advantages and disadvantages of using PortletSession

Even though PortletSession was a preferred way to achieve inter-portlet communication in Portlet 1.0 days, it still has many advantages in Portlet 2.0 world.

Table 2 describes the advantages and disadvantages of using PortletSession as the means for communication between portlets.

Table 2 describes the pros and cons of using PortletSession for inter-portlet communication, which you should consider before deciding the approach that you want to use for communication between portlets.

NOTE

Some portal servers provide additional features to support the sharing session attributes between the portlets in different portlet applications. For instance, you can share the APPLICATION_SCOPE session attributes with portlets in other portlet applications using the session.shared.attributes property in the portal-ext.properties file. Note that such features are portal specific in nature and will result in portability issues.

Summary

In this article, we discussed how PortletSession, public render parameters, and portlet events can be used by portlets to coordinate with other portlets in the web portal. It is hardly possible to create a web portal with portlets that work in silos; therefore, it is important to carefully choose the inter-portlet mechanism that fits your web portal requirements. You may use three inter-portlet communication approaches in your web portal depending on the communication needs of the portlets. One of the biggest advantages of having portlets that communicate with each other is that such communication enriches the users’ experience of the web portal. Another advantage is that, at any given time, portlets reflect the content that is relevant in the context of user actions.

Filed Under: Java Tagged With: Portlets

Accessing Portlet-specific Objects in JSP Pages

April 30, 2011 by Krishna Srinivasan Leave a Comment

This article is based on Portlets in Action, to be published June 2011. I t is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) ebooks and pbooks. MEAPs are sold exclusively through Manning.com. All print book purchases include an ebook free of charge. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information.

also read:

  • Java EE Tutorials
  • Servlets Interview Questions
  • New Features in Servlets 3.0
  • Asynchronous Servlets in Servlets 3

Introduction

In a lot of cases, JavaServer Pages (JSPs) may rely on JSP implicit objects to achieve their functionality. It is perfectly fine to use JSP implicit variables in your JSP pages, but, on the downside, your JSP is dealing with servlet-specific objects (like HttpServletRequest and HttpSession) and not portlet-specific objects (like RenderRequest and PortletSession).

If we add an attribute to RenderRequest, it’s mirrored by HttpServletRequest and vice versa. The same applies to HttpSession and PortletSession. So what difference does it make if we use portlet-specific objects in JSPs? Subtle differences between servlet and portlet API can answer this question. For instance, in your JSP page, you can’t use HttpServletResponse to create a portlet URL (only a RenderResponse object provides methods to create portlet URLs). HttpServletRequest can’t provide the information about the portlet mode and the window state (PortletRequest provides methods to obtain the portlet mode and the window state). This is like rain and freezing rain—both are forms of precipitation with the only difference in what happens when raindrops hit the ground.

In general, your JSP pages will use a combination of portlet and servlet objects to generate content. For instance, if you want to set the expiration time for the content in the JSP page, you will use the RenderResponse portlet object. If you need to obtain the value of an APPLICATION_SCOPE portlet session attribute, you may prefer to use session (which refers to HttpSession object) or sessionScope (which is a java.util.Map of session attributes stored in HttpSession object) for a JSP implicit object to obtain its value.

NOTE

JSPs included by portlets have access to JSP implicit objects because portlet application is also a web application.

The name defineObjects gives the impression that it can be used by JSP developers to define custom objects in their JSP pages, but that’s not the case. The defineObjects tag of portlet tag library provides JSPs with access to portlet objects like RenderRequest, RenderResponse, PortletSession, and so on. Table 1 lists the scripting variables (and their type) that are available to JSP pages that use defineObjects tag.

Table 1 shows the scripting variables defined by the defineObject tag. As you can see, defineObjects provides JSP pages with all Portlet 2.0 API objects they’ll ever need to use portlet-specific features. In JSP pages, you’ll usually use a combination of JSP implicit objects and the implicit objects made available by defineObjects tag. You’ll probably never use actionRequest, actionResponse, eventRequest, and eventResponse objects in your JSP pages because the portlet container ignores the content written out to the response in action and event processing phases.

NOTE

defineObjects tag doesn’t define any attributes.

The sample Book Catalog portlet in this article uses scripting variables introduced by defineObjects tag to show the debugging information, as shown earlier in figure 1.

Listing 1 shows debug.jsp page and is included by all JSP pages in the Book Catalog portlet. The debug.jsp page prints the information about the portlet mode, the window state, the value of myaction attribute from request, the content expiration time, and so on, most of which is obtained using scripting variables introduced by defineObjects tag.

Listing 1 debug.jsp—Using variables introduced by defineObjects tag
[code lang=”java”]<%@ taglib prefix="portlet" #1
uri="http://java.sun.com/portlet_2_0"%> #1
<%@ page contentType="text/html" isELIgnored="false"
import="javax.portlet.PortletSession"%>
<portlet:defineObjects /> #2
….
Value of myaction request attribute:
${requestScope.myaction} #3
Portlet mode of request:
<%=renderRequest.getPortletMode()%> #4
Window state of request:
<%=renderRequest.getWindowState()%> #5
Content Expiration time:
<%=renderResponse.getCacheControl().getExpirationTime()%> #6
seconds
uploadFolder init parameter value:
<%=portletConfig.getInitParameter("uploadFolder")%> #7
myaction attribute value in PortletSession:
${portletSessionScope.myaction} #8
Search criteria stored in PortletSession:
Book name –
<%=portletSession.getAttribute("bookNameSearchField", #9
PortletSession.APPLICATION_SCOPE)%> #9
Author name –
<%=session.getAttribute("authorNameSearchField")%> #10

#1 Declare portlet tab library
#2 defineObjects tag
#3 myaction HttpRequest attribute
#4 Portlet mode from RenderRequest
#5 Window state from RenderRequest
#6 Cache expiration time from RenderResponse
#7 uploadFolder portlet initialization parameter
#8 myaction PortletSession attribute
#9 bookNameSearchField PortletSession attribute
#10 authorNameSearchField HttpSession attribute[/code]
At #1, the JSP page declares the portlet tag library using the taglib directory. The value of the uri attribute is http://java.sun.com/portlet_2_0 if you want to use Portlet 2.0 tag library. If you are using Portlet 1.0 tag library, specify the value of uri as http://java.sun.com/portlet. The defineObjects tag in Portlet 2.0 introduced additional variables like portletSessionScope, portletSession, and so on, which makes it easy to develop portlets using JSP as the view technology. At #2, the defineObjects tag is used to introduce scripting variables in the JSP page. At #3, the requestScope JSP implicit variable is used to obtain the value of the myaction attribute. At #4, the renderRequest variable is used to obtain the current portlet mode. At #5, the renderRequest variable is used to obtain the window state information. At #6, the renderResponse variable is used to obtain CacheControl object, which, in turn, is used to obtain the expiration time for the generated content. At #7, the portletConfig object is used to obtain the uploadFolder portlet initialization parameter. At #8, the portletSessionScope variable is used to obtain the value of the myaction attribute from PortletSession. At #9, the portletSession variable is used to obtain the value of the bookNameSearchField attribute from APPLICATION_SCOPE of PortletSession. At #10, the session JSP implicit variable is used to obtain the value of the authorNameSearchField attribute from HttpSession. We see here that using the session JSP implicit variable makes it easy to retrieve the APPLICATION_SCOPE attribute stored in PortletSession.

Listing 1 shows that we’ll usually use JSP implicit variables and variables introduced by the defineObjects tag to create JSP pages. If you browse through the pages of the Book Catalog portlet, the debugging information will change to reflect the current value of various attributes displayed by the debug.jsp page.

Summary

In this article, we saw how the portlet tag library tags can be used to simplify development of JSP pages used by portlets. Specifically, we learned how to use JSP implicit variables and variables introduced by the defineObjects tag to create JSP pages.

Filed Under: Java EE Tagged With: JSP, Portlets

Portlets are easy

March 24, 2011 by Krishna Srinivasan Leave a Comment

This article is based on Liferay in Action, to be published 24-March-2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) ebooks and pbooks. MEAPs are sold exclusively through Manning.com. All print book purchases include an ebook free of charge. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information.

Portlets are easyPortlets are how all functionality is implemented in Liferay Portal, as well as in any other Java portal. Liferay is an ideal platform for serving and aggregating applications of all kinds, from collaborative message boards and wikis to sales force automation tools, customer relationship management tools and other business applications, to social applications such as photo sharing and games. The choices are limited only by your ingenuity and imagination, which I believe are practically limitless because I’ve seen the Liferay community doing all of the above and more with Liferay.

So how do you get started writing portlets? We’ll introduce the concept of writing portlets with a very simple example. This should get you started writing portlets according to the Java Portlet Standard.

If you check individual projects into a source code repository, you’ll want to check them out into a fully configured Plugins SDK, because the ant scripts in the projects depend on ant scripts within the Plugins SDK for their functionality. Let’s see how we would create new projects.

Creating a portlet plugin: Hello World

Creating portlets with the Plugins SDK is easy. Your portlet projects reside in the Plugins SDK folder in a folder called portlets. To create a new portlet, first decide what its name is going to be. You need both a project name (without spaces) and a display name (which can have spaces). When you’ve decided on your portlet’s name, you’re ready to create the project. On LUM, from the portlets folder, enter the following command:
[code]./create.sh <project name> "<portlet title>"[/code]
So as a first exercise, let’s create the classic example, which, of course, is Hello World. To create a portlet with a project folder of hello-world and a portlet title of Hello World on LUM, type:
[code]./create.sh hello-world "Hello World"[/code]
On Windows, you would type:
[code]create.bat hello-world "Hello World"[/code]
You should get a BUILD SUCCESSFUL message from Ant, and there will now be a new folder inside the portlets folder in your Plugins SDK. This folder is your new portlet project. This is where you’ll be implementing your own functionality. At this point, if you wish, you can check in this project or your whole Plugins SDK to a source code repository to share your project with others. And, if you’re the command-line-plus-text-editor type of developer, you can get to work right away.

Alternatively, you can open your newly created portlet project in your IDE of choice and work with it there. If you do this, make sure that the project references some .jar files from your Liferay installation or you may get compile errors. Since the ant scripts in the Plugins SDK do this for you automatically, you don’t get these errors when working with the Plugins SDK.

Regardless of which tool you’ve used to add functionality to the plugin, after you’ve implemented some functionality, you’ll want to deploy your plugin to test it.

Deploying the Hello World plugin

You could deploy this portlet to Liferay right now if you wanted to because it’s already a Hello World portlet (how easy was that?). To deploy the portlet, go into its directory at the command prompt and type the following command (on all operating systems):
[code] ant deploy[/code]
The portlet will be compiled and deployed to your running Liferay server. (You do have Liferay Portal running, right?) If you’re watching the logs, you’ll see status messages which look like this:
[code]04:07:41,558 INFO [AutoDeployDir:176] Processing hello-world-portlet-6.0.0.1.war
04:07:41,560 INFO [PortletAutoDeployListener:81] Copying portlets for
/home/me/code/bundles/deploy/hello-world-portlet-6.0.0.1.war
04:07:41,635 INFO [PluginPackageUtil:1347] Checking for available updates
Expanding: /home/me/code/bundles/deploy/hello-world-portlet-6.0.0.1.war into
/home/me/code/bundles/tomcat-6.0.18/temp/20100128040741564
Copying 1 file to /home/me/code/bundles/tomcat-6.0.18/temp/20100128040741564/WEB-INF
Copying 1 file to /home/me/code/bundles/tomcat-6.0.18/temp/20100128040741564/WEB-INF/classes
Copying 1 file to /home/me/code/bundles/tomcat-6.0.18/temp/20100128040741564/WEB-INF/classes
Copying 1 file to /home/me/code/bundles/tomcat-6.0.18/temp/20100128040741564/WEB-INF
Copying 1 file to /home/me/code/bundles/tomcat-6.0.18/temp/20100128040741564/META-INF
Copying 24 files to /home/me/code/bundles/tomcat-6.0.18/webapps/hello-world-portlet
Copying 1 file to /home/me/code/bundles/tomcat-6.0.18/webapps/hello-world-portlet
Deleting directory /home/me/code/bundles/tomcat-6.0.18/temp/20100128040741564
04:07:43,263 INFO [PortletAutoDeployListener:91] Portlets for
/home/me/code/bundles/deploy/hello-world-portlet-6.0.0.1.war copied successfully. Deployment
will start in a few seconds.
04:07:44,827 INFO [PortletHotDeployListener:250] Registering portlets for hello-world-portlet
04:07:46,729 INFO [PluginPackageUtil:1391] Finished checking for available updates in 5092 ms
04:07:48,839 INFO [PortletHotDeployListener:376] 1 portlet for hello-world-portlet is
available for use[/code]
When you see the available for use message, your plugin is deployed and can be used immediately. This applies to all plugin types, except for the Ext plugin.

To add the plugin to a page, log in to Liferay Portal using the administrative credentials (user name: test@liferay.com; password: test). From the Dockbar, select Add > More. Your generated portlet project by default is placed in the Samples category (we’ll see how to change this later). Open this category and you should see your portlet displayed similar to figure 1.

By default, portlets are generated as instanceable portlets, so you’ll see your portlet appear with the green icon. Drag it out onto the page. It should look like figure 2.

Obviously, it’s very easy to create a Hello World portlet: we didn’t even have to write any code. We’ll, of course, move on to a more functional portlet shortly but, for now, congratulations! You created your first portlet in less than five minutes.

We could go through all of the other types of plugins and create projects for them, but the process is exactly the same: go into the folder for the plugin type and use the Create script to create a new project. Once you’ve worked on the project, you deploy it in exactly the same manner—using the ant deploy command.

Making Hello World into Hello You

Open the Hello World project that you’ve just created. We’re going to turn this into the Hello You portlet.

Configuring Hello You

The first thing you should take a look at is the portlet.xml file, which you’ll find in the WEB-INF folder. This is the configuration file for the portlet. You’ll find a line in there that looks like this:
[code lang=”xml”]<portlet-class>com.liferay.util.bridges.mvc.MVCPortlet</portlet-class>[/code]
This defines what Java class implements the portlet. By default, projects are generated to use Liferay’s MVCPortlet, which we’ll get to later. It has certain benefits to the experienced developer, but it also abstracts much of the portlet lifecycle from you, which we don’t want to do just yet. So we’re going to implement our own portlet class the way the portlet specification recommends so that you can get familiar with the Portlet API and then move past it to the MVCPortlet and to other frameworks if you wish.

Since we aren’t going to use MVCPortlet, we have to change this line to point to the portlet class we’re going to create. So, modify this line so that it looks like this:
[code]<portlet-class>com.liferayinaction.portlet.HelloYouPortlet</portlet-class>[/code]
Next, we need to tell the portal that our portlet implements edit mode as well as view mode (it assumes view mode; otherwise there would be no point to your portlet). So change the <supports> tag in your portlet.xml so it reads like this:
[code lang=”xml”]<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode>
</supports>[/code]
You may have noticed in portlet.xml another tag called <init-param/>. This tag, as you’ve probably figured out, defines initialization parameters that can be used in your portlet. The default project defines a parameter called view-jsp, which defines the location of the JSP file that will be used to display the portlet in the view mode. This parameter can thus be used in the portlet class to forward processing over to the view.jsp file in the project. This worked in the initial portlet because this functionality was implemented already in MVCPortlet; now that we’re using our own portlet class, we’ll have to implement it ourselves.

Below the definition of your portlet class, add the additional initialization parameter below the existing one like this:
[code lang=”xml”]<init-param>
<name>edit-jsp</name>
<value>/edit.jsp</value>
</init-param>[/code]
Imagine Darth Vader’s voice saying “All of our configuration is now complete.” We can now start implementing the logic of the portlet.

Create a package in your src folder called com.liferayinaction.portlet. In this package, create a Java class called HelloYouPortlet.java. This class will extend the GenericPortlet class, which is included with the Portlet API and is available in every portal implementation. So far, your class should look like the following code.
[code lang=”java”]package com.liferayinaction.portlet;
import javax.portlet.GenericPortlet;
public class HelloYouPortlet extends GenericPortlet {
}[/code]

Portlet initialization and implementing view mode

The first thing we want to do is implement the Portlet API’s init() method to pull the values from our initialization parameters into our portlet class. All we need to do is define two instance variables to hold these values and then implement the method:
[code]protected String editJSP;
protected String viewJSP;
public void init() throws PortletException {
editJSP = getInitParameter("edit-jsp");
viewJSP = getInitParameter("view-jsp");
}[/code]
Easy, right? We get access to the getInitParameter() method because we’re extending an existing class in the Portlet API. So, anything that is in those initialization parameters gets pulled into these variables.

Now we can actually implement the default view of our portlet. This is done by implementing a method called doView(). As you can imagine, there are similar methods for the other portlet modes, and we’ll also be implementing doEdit(). The functionality for this mode is simple: we want to retrieve a preference that may or may not have been stored for the logged-in user. If we don’t find one, we’ll simply print “Hello!” If we do find one, we’ll print a message that takes that preference and displays it in the message. So, if the user’s name is Mortimer Snerd, we’ll print “Hello Mortimer Snerd!”

Listing 1 The default view of your portlet

[code lang=”java”]public void doView(RenderRequest renderRequest,
RenderResponse renderResponse)
throws IOException, PortletException {
PortletPreferences prefs = renderRequest.getPreferences();
String username = (String)prefs.getValue("name", "no");
if (username.equalsIgnoreCase("no")) {
username="";
}
req.setAttribute("userName", username);
include(viewJSP, renderRequest, renderResponse);
}[/code]
In this code, we first grab the PortletPreferences and check to see if the preference is there. The method for getting the preferences wants to know what the preference you’re looking for is called as well as a value to return if it can’t find the preference. So we provide name for the preference and no for the value to return if the preference isn’t found.

If we find a name, we store it as an attribute in the request. If not, we simply store an empty string. We then forward to the view.jsp file that was previously defined in our portlet.xml file.

Note that we’re using some objects here that are very similar to HttpServletRequest and HttpServletResponse, both of which you’re likely already familiar with. These are very similar to their servlet counterparts in that you can set parameters and attributes, retrieve information about the portlet’s environment, and more. In our case, we’re retrieving an object called PortletPreferences from the portlet instance.

We’re also calling a convenience method called include(), which looks like listing 2.

Listing 2 Shortening code with an include() convenience method

[code lang=”java”]protected void include(
String path, RenderRequest renderRequest,
RenderResponse renderResponse)
throws IOException, PortletException {
PortletRequestDispatcher portletRequestDispatcher =
getPortletContext().getRequestDispatcher(path);
if (portletRequestDispatcher == null) {
_log.error(path + " is not a valid include");
} else {
portletRequestDispatcher.include(
renderRequest, renderResponse);
}
}[/code]
Just like you can in a servlet-based web application, you can forward request processing to a JSP from a portlet. And just like in a servlet-based web application, you have to chain a whole bunch of methods together in order to accomplish it. To make our code neater, we can simply create a convenience method called include(), which chains all those methods together for us so that all we have to do is call this one method (which has a nice, short name) to forward processing to a JSP.

We’ve included a check here to make sure that the PortletRequestDispatcher we get out of the PortletContext is not null. If I’s null, we log that. To use this method, therefore, we’ll also have to enable logging in our portlet. Liferay ships with Apache’s Commons Logging classes, which make it easy to add log entries from our portlets. We only need to add an instance variable to the class for our _log object:
[code]private static Log _log = LogFactory.getLog(HelloYouPortlet.class);[/code]
To complete the view mode of this portlet, we now have to implement the JSP to which we’re forwarding, which you can see in its entirety in listing 3.

Listing 3 Implementing the JSP for view mode

[code lang=”html”]<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<jsp:useBean id="userName" class="java.lang.String" scope="request"/> #1

<portlet:defineObjects />

<p>This is the Hello You portlet.</p>
<p>Hello <%=userName %>!</p>
#1 Gets the bean out of the request[/code]
<portlet:defineObjects />

<p>This is the Hello You portlet.</p>
<p>Hello <%=userName %>!</p>
#1 Gets the bean out of the request

In the first line, we declare the portlet tag library. This again is a part of the Portlet API and is a standard across all portals. The next line should look familiar: we pull a bean out of the request that we had made available in the doView() method of our portlet (#1). There’s no difference in how this is done versus doing it with a servlet. The tag in the third line comes from the portlet tag library, which we declared in the first line. The defineObjects tag registers several objects with the JSP that may be useful: renderRequest, renderResponse, and portletConfig.
About backward compatibility The tag library declaration above is the declaration for Portlet 1.0. This has been done for backward compatibility, as we’re not using any features in this first portlet that require Portlet 2.0. This portlet, therefore, can be deployed on any Portlet 1.0 container (such as Liferay 4.4.x) or any Portlet 2.0 container (such as Liferay 5.0 and above).
The Portlet API’s RenderRequest and RenderResponse objects correspond to the HttpServletRequest and HttpServletResponse objects with which you may be familiar, and we’ve already used these in our portlet class. The PortletConfig object corresponds roughly with the ServletConfig object you would use in a Servlet, in that it holds data about the portlet and its environment. Because you may need to use these objects in your JSP’s display logic, these three variables are defined through the defineObjects tag, and it’s a good idea to always put this tag at the top of your JSPs.

Otherwise, the logic of this JSP is very simple. We pull the bean we stored in the request and print a “Hello” message. If the bean has a value, that value will be printed after the message; if not, nothing will be printed.

At this point, view mode is complete. You can actually deploy the portlet as it is and it will display a hello message. Since we haven’t implemented edit mode yet, though, it won’t have any functionality, so that’s what we’ll do next.

Implementing edit mode

Before we jump into the code for the edit mode, I need to tell you something about URLs in portlet applications. Most web developers are used to manipulating the URL directly. That’s not something you can do in a portlet application. In most cases, portlet URLs are linked with Portlet actions, which cause the portlet to do some processing. Portlet actions are defined using a special portlet URL object called an ActionURL. Because a portlet is a fragment of a page that is assembled at runtime by the portlet container, developers cannot simply define their own URLs like they can in regular web applications. Instead, they must be created programmatically. This is a bit of a paradigm shift, but it’s fairly easy to make the transition. It’s important to know that the contents of URLs must be generated by the portal server at runtime. Why? So that there are no conflicts between URLs generated by different portlets.

For example, consider a search portlet that sits on a page. This portlet can search for any uploaded content. Say, another portlet is placed on that page by a user. This other portlet contains a list of customers and has a search box at the top.

If developers knew ahead of time that these portlets would be placed on the same page, they could make sure that the URLs to the two separate search functions were different. But they didn’t know ahead of time that a portal administrator would do this, and so both search URLs point to /search in the application’s context. Can you see how there would be a conflict? Which application’s search would get called?

For this reason, the Portlet API provides URL objects. Developers can create URL objects programmatically and even set parameters in them. This allows the portlet container to generate the actual URL strings at runtime, preventing any conflicts like the one mentioned above. Since our implementation of edit mode consists of a very simple form that users will fill out and submit, we need a URL for the submit button. For this reason, we’ll have to create one using the API. So our doEdit() method in listing 4 reflects this.

Listing 4 Implementing doEdit() in our portlet

[code lang=”java”]public void doEdit(RenderRequest renderRequest,
RenderResponse renderResponse)
throws IOException, PortletException {
renderResponse.setContentType("text/html");
PortletURL addName = renderResponse.createActionURL();
addName.setParameter("addName", "addName");
renderRequest.setAttribute("addNameUrl", addName.toString());
include(editJSP, renderRequest, renderResponse);
}[/code]
When you add the code above, you’ll also have to add the import javax.portlet.PortletURL.

More about backward compatibility
The first line of code in listing 4, which sets the content type, is only required in the 1.0 (JSR-168) version of the API. It doesn’t hurt anything, so we have left it in the method above to maintain backward compatibility but, if you’re using Portlet 2.0 (JSR-286), it’s not necessary.

We’ve created an ActionURL and added a parameter called addName to it. We then put the URL in the request object so that it may be used in the JSP to which we’ll be forwarding the processing.

Let’s implement the JSP for the edit mode next. Create a file in docroot called edit.jsp. Remember that we earlier pointed to this file using an initialization parameter in portlet.xml. Listing 5 shows the edit.jsp file.

Listing 5 The JSP for edit mode

[code lang=”html”]<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<jsp:useBean class="java.lang.String" id="addNameUrl" scope="request" />
<portlet:defineObjects />
<form
id = "<portlet:namespace />helloForm"
action="<%=addNameUrl %>"
method="post">
<table>
<tr>
<td>Name:</td>
<td><input type="text" name="username"></td>
</tr>
</table>
<input type="submit" id="nameButton" title="Add Name" value="Add Name">
</form>[/code]
In listing 5, we first declare the tag library for the Portlet API as we did before and we then make our URL available to the JSP using the useBean tag to retrieve it from the request object and place it in a variable called addNameUrl.

After this is a simple HTML form. Notice that we use a portlet tag called namespace in front of our form name. This is done for similar reasons that portlet URLs exist: you could have multiple forms with the same name on the page and then they would conflict with each other. Using this tag, you allow the portal server to prepend a unique string to the front of your form’s name, thereby ensuring that no other portlet will contain a form with the same name as yours.

Note also that the form’s action is set to the value of the action name parameter in the ActionURL we created in the portlet class and then retrieved as a bean in the JSP. This URL has the parameter addName in it, which will be captured by our processAction method when this form is submitted so that processing can be directed to the right place.

Speaking of processAction, that is now the only missing element in our portlet. This method is part of the standard Portlet API. The processAction method is there to provide a place where portlet actions can be processed. A default implementation is provided with the API, but we’re going to override it for this portlet and provide our own implementation.

Portlet URLs can be of two types: a RenderURL or an ActionURL. A RenderURL simply tells the portlet to render itself again. Whatever parameters have been defined for the portlet at that time take effect and the portlet redraws itself. An ActionURL immediately forwards processing to the processAction method, where logic can be in place to determine which action has been taken by the user and then the appropriate processing can occur. We’ll implement our own version of this so that we can see how it works and then, later on, we’ll take advantage of other (better) implementations. Since we have only one action, the logic will be pretty simple, as you can see in listing 6.

Listing 6 Processing a portlet action

[code lang=”java”]String addName = actionRequest.getParameter("addName");
if (addName != null) {
PortletPreferences prefs = actionRequest.getPreferences();
prefs.setValue("name", actionRequest.getParameter("username"));
prefs.store();
actionResponse.setPortletMode(PortletMode.VIEW);
}[/code]
You’ll also need to add the following two imports to the top of your class:
[code]import javax.portlet.PortletPreferences;
import javax.portlet.PortletMode;[/code]
This code searches for a parameter in the portlet’s ActionRequest object called addName. We created this parameter earlier as part of an ActionURL in our doEdit() method. Simply by having the form’s action point to this URL, processing is directed to the four lines of code in the if statement. We could just as easily have called a different method instead, which is what you would normally do in a larger portlet so that you can keep only action processing logic here.

In any case, the parameter—called username—will be found in the request because it was a field on the form. The Portlet API is then accessed in order to store a preference for this particular user. The preference is called name and we use whatever value was in the parameter. Yes, I know: we’re not doing any field validation. Normally you would do that before storing anything, but I wanted to keep this example as simple as possible. This key/value pair will now be stored for that portlet/user combination.

The last thing this code does is set the portlet mode back to view mode. When that is done, doView() will be called and the user will now get the “Hello <name>” message.

To summarize, we now have all of the processing for the portlet’s edit mode in place. The doEdit() method creates a URL with an action name parameter of addName. Processing is then forwarded to the edit.jsp file where this parameter is used as the action of a form. The form contains one field, which the user will use to type his or her name. When the form is submitted, the portlet’s processAction method will run and retrieve the action’s name parameter, which will have the value addName. Checking for this value leads us to code that stores the name the user submitted as a PortletPreference. To keep the example simple, we have not implemented any validation on the data submitted.

Rather than look at it piecemeal as we did above, it’s sometimes easier to see how things work by showing the whole example. So listing 7 shows what the entire portlet should look like.

Listing 7 The complete Hello You portlet

[code lang=”java”]package com.liferayinaction.portlet;
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.PortletMode;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class HelloYouPortlet extends GenericPortlet {
public void init() throws PortletException {
editJSP = getInitParameter("edit-jsp");
viewJSP = getInitParameter("view-jsp");
}
public void doEdit(RenderRequest renderRequest,
RenderResponse renderResponse)
throws IOException, PortletException {
renderResponse.setContentType("text/html");
PortletURL addName = renderResponse.createActionURL();
addName.setParameter("addName", "addName");
renderRequest.setAttribute("addNameUrl", addName.toString());
include(editJSP, renderRequest, renderResponse);
}
public void doView(RenderRequest renderRequest,
RenderResponse renderResponse)
throws IOException, PortletException {
PortletPreferences prefs = renderRequest.getPreferences();
String username = (String) prefs.getValue("name", "no");
if (username.equalsIgnoreCase("no")) {
username = "";
}
renderRequest.setAttribute("userName", username);
include(viewJSP, renderRequest, renderResponse);
}
public void processAction(
ActionRequest actionRequest,
ActionResponse actionResponse)
throws IOException, PortletException {
String addName = actionRequest.getParameter("addName");
if (addName != null) {
PortletPreferences prefs =
actionRequest.getPreferences();
prefs.setValue(
"name", actionRequest.getParameter("username"));
prefs.store();
actionResponse.setPortletMode(PortletMode.VIEW);
}
}
protected void include(
String path, RenderRequest renderRequest,
RenderResponse renderResponse)
throws IOException, PortletException {
PortletRequestDispatcher portletRequestDispatcher =
getPortletContext().getRequestDispatcher(path);
if (portletRequestDispatcher == null) {
_log.error(path + " is not a valid include");
} else {
portletRequestDispatcher.include(
renderRequest, renderResponse);
}
}
protected String editJSP;
protected String viewJSP;
private static Log _log = LogFactory.getLog(HelloYouPortlet.class);
}[/code]

Deploying and testing your portlet

Because we used the Plugins SDK to create this project, it came with its own Ant script, which makes it very easy to build and deploy the project. If your IDE supports Ant, you can deploy the project right from within your IDE. If you’re not using an IDE, you can run a simple command to deploy your project.

First, start your Liferay server. Again, if you’re using an IDE and have followed the instructions from the previous chapter, you can do this right from within your IDE. Once Liferay has started, keep a window open to Liferay’s console so you can watch the deploy take place.

Next, run the deploy task from the Ant build script. To do this from the command line (on any operating system), issue the following command from the project folder:
[code] ant deploy[/code]
Once you receive the BUILD SUCCESSFUL message, turn your attention to the Liferay console. You should see your portlet deploy right away.

Your new portlet is now indistinguishable from any other portlet deployed in Liferay. Go to http://localhost:8080 and log in using the administrative credentials:

User Name: test@liferay.com

Password: test

From the Dockbar and click Add > More. You’ll see many categories of portlets displayed. Open the one labeled Sample. You’ll see the Hello World portlet listed there. Drag it off the list and drop it in the right-most column, if it’s not there already. If you followed along with the previous chapter, the portlet should already be there.

You’ll now see your portlet displayed. You can close the Add > More window by clicking the red X in its top right corner.

The default message “Hello!” is being displayed in the portlet. This is the way it’s supposed to function: we haven’t set our Portlet Preference yet, so the portlet does’nt know our name. To get to Edit Mode, click the button in the title bar of the portlet that has a wrench on it, and then click the Preferences link. (Liferay Portal displays a portlet’s edit mode as a Preferences menu item.) You’ll be brought to the portlet’s edit mode and your edit.jsp will be displayed.

Type your name and click the Add Name button. Your Portlet Preference will be stored, and because we changed the mode of the portlet back to View in our processAction method, the portlet will redisplay itself in view mode. Because our Portlet Preference is now set, the portlet will display the name we entered.

Congratulations! You have just written your first portlet!

Changing the portlet’s name and category

Notice that, when you added the portlet, you had to select it from the Sample category in the Add > More window. You also had to add the Hello World portlet, but now our portlet is called Hello You. The portlet is in a suboptimal category because the generated portlet project defaults to this category, and the portlet has the wrong name because we created Hello World first. If you’d like to create your own category for your portlet, this is easy to do. At the same time, we also want to rename the portlet so that it’s no longer called Hello World. We can do these things by editing three XML files:

  • portlet.xml
  • liferay-portlet.xml
  • liferay-display.xml

Renaming the portlet

First, let’s change the name of the portlet. Open portlet.xml, which is in your WEB-INF folder. There are two places in this file where we need to change the name. The first takes effect at a system level, and the second takes effect for the portlet title.

Find the two lines in the file that look like this:
[code lang=”xml”]<portlet-name>hello-world</portlet-name>
<display-name>Hello World</display-name>[/code]
Change them so that they read like this:

[code lang=”xml”]<portlet-name>hello-you</portlet-name>
<display-name>Hello You</display-name>[/code]

Next, find the the <portlet-info> section of the file:

[code lang=”xml”]<portlet-info>
<title>Hello World</title>
<short-title>Hello World</short-title>
<keywords>Hello World</keywords>
</portlet-info>[/code]

Change it so that it reads like this:
[code lang=”xml”]<portlet-info>
<title>Hello You</title>
<short-title>Hello You</short-title>
<keywords>Hello You</keywords>
</portlet-info>[/code]

Next, open liferay-portlet.xml, which is in the same folder. Find the following line, which is in the <portlet> tag:

[code lang=”xml”]<portlet-name>hello-world</portlet-name>[/code]

Change it so it reads:
[code lang=”xml”]<portlet-name>hello-you</portlet-name>[/code]

Creating a custom category

Finally, in the same WEB-INF folder, you’ll find a file called liferay-display.xml. This file controls the category under which your portlet appears in the Add > More window. Open this file and you’ll see the code shown in the following listing.

Listing 8 Changing the category for your portlet

[code lang=”xml”]<?xml version="1.0"?>
<!DOCTYPE display PUBLIC "-//Liferay//DTD Display 6.0.0//EN"
"http://www.liferay.com/dtd/liferay-display_6_0_0.dtd">
<display>
<category name="category.sample">
<portlet id="hello-you" />
</category>
</display>[/code]
Change the category name to something else, like My Portlets. The code would then read:
[code lang=”xml”]<display>
<category name="My Portlets">
<portlet id="hello-you" />
</category>
</display>[/code]
Now go ahead and deploy your portlet again. Refresh the page. You’ll see that an interesting thing has happened to your portlet, shown in figure 3.

Your portlet no longer exists. You just renamed your portlet to Hello You, but Liferay thinks a Hello World portlet is on the page because, well, you put it there. Of course, now Liferay can’t find it, so it displays this message. So, what you’ll have to do is remove the portlet from the page and add your newly renamed portlet to the page instead. To remove the portlet, just click the x.

Next, open the Add > More window. You’ll see your new category displayed, and your portlet is now displayed there, as in figure 4.

You can now drag the portlet over to the page. When you do, notice what it says now (figure 5).

The preference you stored earlier when the portlet was named Hello World was saved for that portlet. Now that you have renamed it, that portlet no longer exists. For all intents and purposes, even though the code is exactly the same, this is now a new portlet according to Liferay, so Liferay treats it as such. Its title bar also now properly displays “Hello You,” because you configured it that way in the portlet.xml file.

Summary

You’ve just created a portlet according to the Java standard. This portlet really doesn’t do very much, but it serves as a good introduction to several highly used features of the portlet API. We’ve used only Portlet 1.0 features in this portlet, so you could deploy it on containers that support either Portlet 1.0 (like Liferay 4.4.x and below) or Portlet 2.0 (like Liferay 5.0.x and above). The skills you’ve learned here will provide a good foundation for creating more complex portlet projects.

Filed Under: Misc Tagged With: Portlets

Follow Us

  • Facebook
  • Pinterest

As a participant in the Amazon Services LLC Associates Program, this site may earn from qualifying purchases. We may also earn commissions on purchases from other retail websites.

JavaBeat

FEATURED TUTORIALS

Answered: Using Java to Convert Int to String

What is new in Java 6.0 Collections API?

The Java 6.0 Compiler API

Copyright © by JavaBeat · All rights reserved