Taglib

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" />