JSP

Liferay allPortletsReady event not firing

Today I stumbled upon a problem where I noticed that on some of my pages my portlet was acting weird and the culprit of the problem was the Liferay specific javascript “allPortletsReady” event not firing. I was using the latest version of Liferay 6.2 CE.

So I debugged and Googled around and went through a pretty large array of possible problems for why the allPortletsReady was not working for other people.

Some results suggested that the Related Assets portlet might cause the problem – That’s not the case this time though as I wasn’t using that portlet on my pages.

Next up on the list is Notifications Portlet and sure enough I had no Notification Portlet on those pages either.

Finding no obvious solutions using quick searches on Google and StackOverflow I decided to start testing and debugging. So I created a new clean page and added my portlet on that one. This time the portlet had it’s “allPortletsReady” event nicely firing so I now know that my portlet works on new and clean pages.

Then I deleted all portlets, including my own, from an old page where the portlet was not getting it’s allPortletsReady Javascript event called and then I added my portlet back in there. This time the Javascript event remained unfired and problem was still around the corner.

So by now we know that it works on clean new pages and does not work on old pages even after removing all portlets. I even tried switching themes which had no result.

Liferay allPortletsReady Solution (One of many)

Finally it dawned upon me – there has to be a difference on the pages between the new and old page – I checked the page’s embedded portlets section and discovered that even though I no longer had a Login portlet on those pages, they still had Liferay built-in Login portlet ID 58 listed there with some preferences saved. I removed those preferences and sure enough the allPortletsReady started firing again as normal.

Here’s a screenshot of the embedded portles section (I already removed the Login portlet from the list):
Liferay page embedded portlets

So it seems Liferay has some kind of an issue with old embedded Portlet preferences sticking around and causing issues with our Javascript events.


Solution: Remove old unused embedded portlet preferences from the page.

If you have a question or having trouble getting this thing working then feel free to write me a comment and I’ll do my best to help you out. If you would like to read more about Liferay related subjects then also make sure to comment on that and if you liked what you read then make sure to subscribe – It’s FREE!

Liferay portlet file upload tutorial

Here’s a Liferay portlet file upload tutorial to show you how to handle file uploading by clients.
First we need to define our upload form JSP. This can be shown using Liferay MVCPortlet’s default view.jsp.
We will define our upload form as an AlloyUI form element and w

view.jsp


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui"%>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<portlet:defineObjects />

<portlet:actionURL name="upload" var="uploadFileURL"></portlet:actionURL>

<aui:form action="<%= uploadFileURL %>" enctype="multipart/form-data" method="post">

	<aui:input type="file" name="fileupload" />
	
	<aui:button name="Save" value="Save" type="submit" />

</aui:form>

And now we need to handle the upload action that we are calling by submiting this form.
Note some important parts that people often miss in their code, like checking if there’s enough room on the device to actually store the file and refuse additional file uploads when the device has less than 1GB of free space.

Full example class


import java.io.File;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;

import org.apache.commons.io.FileUtils;

import com.liferay.portal.kernel.upload.UploadPortletRequest;
import com.liferay.portal.util.PortalUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;

public class RelatedFilesPortlet extends MVCPortlet {

	private final static int ONE_GB = 1073741824;
	
	private final static String baseDir = "/tmp/uploaded/";
	
	private final static String fileInputName = "fileupload";

	public void upload(ActionRequest request, ActionResponse response)
			throws Exception {

		UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(request);

		long sizeInBytes = uploadRequest.getSize(fileInputName);

		if (uploadRequest.getSize(fileInputName) == 0) {
			throw new Exception("Received file is 0 bytes!");
		}

		// Get the uploaded file as a file.
		File uploadedFile = uploadRequest.getFile(fileInputName);

		String sourceFileName = uploadRequest.getFileName(fileInputName);

		
		// Where should we store this file?
		File folder = new File(baseDir);

		// Check minimum 1GB storage space to save new files...
		
		if (folder.getUsableSpace() < ONE_GB) {
			throw new Exception("Out of disk space!");
		}

		// This is our final file path.
		File filePath = new File(folder.getAbsolutePath() + File.separator + sourceFileName);

		// Move the existing temporary file to new location.
		FileUtils.copyFile(uploadedFile, filePath);
	}

}

Java tutorial on how to make a Portlet

Java tutorial on how to create a simple Hello world Portlet. Let’s start with a simple overview of files. Depending on your project structure and IDE your source code can be structured differently but in all normal cases you will have a WEB-INF folder and inside of that you should have a portlet.xml file. This is the file that defines what Portlets are included in our¬†¬†application. You can have more than one portlet in one application.

portlet.xml


<?xml version="1.0"?>

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
	version="2.0">
	<portlet>
		<portlet-name>hello-world-tutorial</portlet-name>
		<display-name>Hello World Tutorial</display-name>
		<portlet-class>com.example.package.HelloWorldPortlet</portlet-class>
		<expiration-cache>0</expiration-cache>
		<supports>
			<mime-type>text/html</mime-type>
			<portlet-mode>view</portlet-mode>
			<window-state>normal</window-state>
		</supports>
		<portlet-info>
			<title>Hello World Tutorial</title>
			<short-title>Hello World Tutorial</short-title>
			<keywords>hello world, tutorial</keywords>
		</portlet-info>
		<security-role-ref>
			<role-name>administrator</role-name>
		</security-role-ref>
		<security-role-ref>
			<role-name>power-user</role-name>
		</security-role-ref>
		<security-role-ref>
			<role-name>user</role-name>
		</security-role-ref>
	</portlet>
</portlet-app>	

Now, we also need that class that we reference in portlet.xml. Every portlet needs a class that acts as the Controller in MVC pattern.

HelloWorldPortlet.java

import java.io.*;
import javax.portlet.*;

public class HelloWorldPortlet extends GenericPortlet {

	protected void doView (RenderRequest request, RenderResponse response) throws PortletException, IOException {
		String url = "/view.jsp";
		getPortletContext().getRequestDispatcher(url).include(request,response);  
	}
}

Finally, we also need the view.jsp file, this should go to the same level with WEB-INF folder.

view.jsp


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />

<h2>Hello World</h2>
This is a tutorial portlet. <br />
Your browser seems to be :<b><%=request.getHeader("user-agent")%></b><br />
And we think that your current language is: <b><%=request.getLocale().getDisplayLanguage()%></b> <br />

Have a lovely day.

Please note that we used portlet_2_0 taglib which is JSR 286. If your environment requires an older version, just leave out the _2_0.

Now while this is a perfectly nice portlet, it’s a little bit too simple. For more complex applications I would suggest you use some framework to get a head start. Spring has a lovely Portlet support but you can also use Liferay provided MVCPortlet as your basis for new Portlets, but you can only do that when you develop your applications for Liferay Portal. Frameworks provide both functionality and structure to a project. Struts 2 enforces the MVC pattern and provides lots of functionality, such as custom tags and validating functionality. With Liferay you can use almost any frameworks in the JavaEE space, including Struts, Spring Framework, and JSF.

The benefit of doing a completely vendor-free(Not using any portal specific stuff) portlet with open-source frameworks is that you can deploy the same portlet in either Liferay, JBoss, Websphere Portal or other JSR 286 compliant portals.

Java tutorial

How to create a taglib with JSP’s for Liferay

This is a bit tricky since we want to be able to nicely use our tag library in all our multiple Portlet projects, so the taglib should be a maven dependency. This usually means a Jar file. This is all nice and we can easily fit our Tag classes in the jar. We can also easily fit our TLD file in META-INF folder and it’s nicely available. Now comes the tricky part – What if we want our tag output to be a separate JSP page. Like almost all the Liferay tags are. JSP allows us to access all Liferay theme variables, other taglibs and all other useful things while generating our tag output.

The problem is that you can’t load the JSP from a jar file easily so the JSP’s have to be actually outside of your reusable jar project. So Liferay has an IncludeTag class that we want to extend that provides us with JSP output.

So we end up having 2 projects:

  • One for the Taglib TLD file and actual Tag classes that’s turned into JAR that we can use as a dependency in our other portlet projects.
  • One for the JSP files that is a Hook so the JSP’s are always available.

Here’s the example Tag class, this goes into our “example-userlist-taglib” project.
Notice that we have a JSP path that follows the Liferay convention on naming the files.

import javax.servlet.http.HttpServletRequest;
import com.liferay.taglib.util.IncludeTag;

public class UserList extends IncludeTag {

	private static final boolean _CLEAN_UP_SET_ATTRIBUTES = true;

	private static final String _PAGE = "/html/taglib/example/userlist/page.jsp";

	private String label;

	@Override
	protected String getPage() {
		return _PAGE;
	}

	@Override
	public int doStartTag() {
		return EVAL_BODY_INCLUDE;
	}

	@Override
	protected void cleanUp() {
		setLabel(null);
	}

	@Override
	protected boolean isCleanUpSetAttributes() {
		return _CLEAN_UP_SET_ATTRIBUTES;
	}

	@Override
	protected void setAttributes(HttpServletRequest request) {
		request.setAttribute("example:user-list:label", getLabel());
	}

	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

}

Now an example TLD file on how to define a tag in taglib that should be in /src/main/resources/META-INF/ if you are running a maven based project:


<?xml version="1.0"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
	<tlib-version>1.0</tlib-version>
	<short-name>example</short-name>
	<uri>http://example.com/tld/liferay</uri>
	<tag>
		<name>user-list</name>
		<tag-class>com.example.package.UserList</tag-class>
		<body-content>JSP</body-content>
		<attribute>
			<name>label</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>		
</taglib>

Solution to our JSP loading problem is actually rather simple: Create a Hook project that contains all your taglib JSP’s and deploy that on any Liferay server you need to use your taglib. The files for my userlist tag have to go into META-INF/custom_jsps/html/taglib/example/userlist/ folder for example.

I actually have an init.jsp and a page.jsp file there, examples follow:
init.jsp:


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui"%>
<%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet"%>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme"%>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<%@ taglib uri="http://liferay.com/tld/util" prefix="liferay-util"%>
<%@ page import="javax.portlet.PortletRequest"%>
<%@ page import="javax.portlet.PortletResponse"%>
<%@ page import="javax.portlet.PortletPreferences"%>
<portlet:defineObjects />
<liferay-theme:defineObjects />
<%
PortletRequest portletRequest = (PortletRequest)request.getAttribute(JavaConstants.JAVAX_PORTLET_REQUEST);
PortletResponse portletResponse = (PortletResponse)request.getAttribute(JavaConstants.JAVAX_PORTLET_RESPONSE);

String label = (String)request.getAttribute("example:user-list:label");

%>

and now the userlist tag jsp:


<%@ include file="init.jsp"%>
<div class="userlist">
	<strong><%=label %></strong>:
	<!-- Add code here for listing your users. -->
</div>


So there you have it! Now we can easily use our tag in any portlet jsp, provided we first include our taglib like this:

<%@ taglib uri="http://example.com/tld/liferay" prefix="example" %>

and then we can do:

<example:user-list label="Admin users" />