« Back

Tagfiles VS Taglibs

Company Blogs November 8, 2007 By Brett Swaim Staff

I recently had the realization that I was duplicating a certain set of code across multiple portlets. For those who know me, they will attest that my work motto is to work smart not hard. I hate code duplication with a fiery passion, thus something had to be done. The question was what? After some thought, I decided that I needed to make a taglib. I started coding it, and had a realization... a tagfile would be much easier!

So what is a tagfile? Tagfiles were introduced with JSP 2.0. They were created because sometimes a taglib is jsut too much work for what it does. For many simple and even some complex operations, tagfiles are like coding magic.  Let's compare the two:

  • Taglibs:
  • Class driven
  • Uses a tld that can be from any site
  • JSP 1.1 compatible.
  • Tagfiles
    • JSP driven
    • No tld required
    • Works immediately without any compile
    • Really easy!

So if you can't guess, I chose to use a tagfile. Before I show you the code, let's do a high level overview of what is required for tagfiles.

  1. You
  2. A tags folder under WEB-INF (/WEB-INF/tags)
  3. A folder under that with the name of the tag
  4. a .tag file

So lets make a basic Hello World tagfile that outputs the text "Hello World in (Insert Year Here)".

 

Step 1: create /WEB-INF/tags/hello-world/hello.tag
Step 2: enter the following in hello.tag:

<%@attribute name="year" required="true"%>

Hello World in <%=year%>

Step 3: Edit your JSP that you want the hello world to show up in. Enter this code:

<%@ taglib prefix="showMore" tagdir="/WEB-INF/tags/hello-world" %>
<showMore:hello />

That should be all that's required. Refresh your jsp. Eat cake.

So sure, that's cool and all... but you could EASILY accomplish the same this with a simple file include. Where is the excitement? The drama? It's right here, you just don't know it yet.

Let's do a more useful example. Let's say that you hate using our <portlet:actionURL /> taglib... you want something easier and cleaner. I know in my IDE it always breaks my <a href's /> when I put it in. Time to fix that. This tagfile will do the following: create a Struts url (maximized or minimized) to a struts path, if a clean way that IDEs understand.

Step 1: create init.tag under hello-world
Step 2: enter the following in init.tag

<%@ tag import="com.liferay.portal.kernel.security.permission.ActionKeys" %>
<%@ tag import="com.liferay.portal.kernel.util.StringPool" %>
<%@ tag import="com.liferay.portal.service.permission.PortletPermissionUtil" %>

<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
<%@ taglib uri="http://struts.apache.org/tags-nested" prefix="nested" %>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>

<%@ tag import="com.liferay.portal.util.PortalUtil" %>
<%@ tag import="com.liferay.portal.util.PortletKeys" %>
<%@ tag import="javax.portlet.WindowState" %>
<%@ tag import="java.text.DateFormat" %>
<%@ tag import="java.util.List" %>

<%@attribute name="maximized" type="java.lang.Boolean"%>
<%@attribute name="struts_path" required="true" %>
<%@attribute name="actionUrl" type="java.lang.Boolean"%>

<portlet:defineObjects />
<liferay-theme:defineObjects />

<%
    String currentURL = PortalUtil.getCurrentURL(request);
%>

Notice that this looks a lot like a regular liferay init.jsp... that's because it almost is! We just replace <%@page %> with <%@tag %>.

Step 3: edit hello.tag with the following code:

<%@include file="init.tag"%>

<%
    String windowState=null;
    if (maximized != null) {
        windowState = WindowState.MAXIMIZED.toString();
    }
    else {
        windowState = WindowState.NORMAL.toString();
    }
%>
<%
    if (actionUrl != null) {
%>
    <portlet:actionURL windowState="<%=windowState%>">
        <portlet:param name="struts_action" value="<%=struts_path%>" />
    </portlet:actionURL>
<%
    }
    else {
%>
    <portlet:renderURL windowState="<%=windowState%>">
        <portlet:param name="struts_action" value="<%=struts_path%>" />
    </portlet:renderURL>
<%
    }
%>

Step 4: Lastly, enter this into your jsp.

<showMore:hello struts_path="/a/view" maximized="true" actionUrl="true"/>

Take note that your struts path will change, and that struts_path is the only one required...

Step 5: Reload your page, enjoy your beautiful link.

Step 6: Enjoy more cake.

Threaded Replies Author Date
That's pretty cool. Traditional taglibs can be... Michael Young November 9, 2007 6:55 AM
Good job Brett! This looks very interesting. Ray Augé November 9, 2007 5:08 PM
great work. I had a similar problem than you:... Sebastián Gurin April 23, 2008 9:52 PM
nevermind my last post. I couldn't solve the... Sebastián Gurin April 24, 2008 6:34 AM
Hey Sabastian, Using tagfiles will work to... Brett Swaim April 24, 2008 10:19 AM
Brett: thanks for the reply. I have posted my... Sebastián Gurin April 25, 2008 7:44 AM
great job! i have the same passion, to... lajos papp April 24, 2008 9:59 AM
Thanks for the heads up, I've adjusted the... Brett Swaim April 24, 2008 10:16 AM
what about "var" <portlet:actionURL> attribute?... Sebastián Gurin April 29, 2008 7:36 AM
I got it. in your init.tag add: <%@attribute... Sebastián Gurin April 29, 2008 8:19 AM
Very nice! Brett Swaim April 29, 2008 9:29 AM
Really nice article! I didn't know about... Thiago Leão Moreira October 19, 2010 6:21 AM

That's pretty cool. Traditional taglibs can be quite painful for the simpler tasks (such as macros like these).

For the more complex tasks, such as dealing with nested content between the tags, the pain is more bearable.
Posted on 11/9/07 6:55 AM.
Good job Brett!

This looks very interesting.
Posted on 11/9/07 5:08 PM.
great work. I had a similar problem than you: two portlets, one extending some of the other pages, but both sharing several jsps. Now I can mantin common jsps only in one portlet... and I learned tagfiles! thank you
Posted on 4/23/08 9:52 PM.
nevermind my last post. I couldn't solve the problem of sharing jsps between portlets... can you point me on how you make it? thanks in advance and excuse my poor english. great article about filetags, anyway...
Posted on 4/24/08 6:34 AM in reply to Sebastián Gurin.
great job!

i have the same passion, to eliminate duplicated code. just a small note: i think you made a small typo in you second code box. you wrote <hello-world:hello /> but probably meant <showMore:hello/>
Posted on 4/24/08 9:59 AM.
Thanks for the heads up, I've adjusted the example.

Brett
Posted on 4/24/08 10:16 AM in reply to lajos papp.
Hey Sabastian,

Using tagfiles will work to share a common jsp between 2 pages. You could also create one and do a simple <%@ include="filenamehere.jsp" %> to include a common file (this is done everywhere in Liferay). Your best bet would be to post a question in the public messageboards about this and shoot me a link so I can answetr it there. I want to try to keep threads in the blogs related to the subject at hand.

Thanks!!

Brett
Posted on 4/24/08 10:19 AM in reply to Sebastián Gurin.
Brett: thanks for the reply. I have posted my problem here: http://www.liferay.com/web/guest/community/forums/message_boards/message/718805

I­ was able to resolve it configuring struts-path for the second portlet to point to the original portlet tiles def... but any other idea is welcome. thank you for your help anyway.
Posted on 4/25/08 7:44 AM in reply to Brett Swaim.
what about "var" <portlet:actionURL> attribute? can it be simulated by your <showMore:hello> custom tag ?
Posted on 4/29/08 7:36 AM.
I got it. in your init.tag add:

<%@attribute name="javaVar" rtexprvalue="false" required="true" %>
<%@ variable name-from-attribute="javaVar"
variable-class="java.lang.Object" alias="var" scope="AT_END"%>

in your hello.tag you must pass var attribute to <portlet:actionURL and <portlet:renderURL like: <portlet:actionURL windowState="<%=windowState%>" var="var">

then in the caller jsp you can get the url like:
<showMore:hello struts_path="/portlet_a/view" maximized="true" actionUrl="true" javaVar="var1"/>

<p>${var1}</p>

another sugestion is to set the portlet path inside the tag file so the user don't hardcode the portlet struts path in its jsp. Inside the tag file you can obtain the portlet struts path with

String portletStrutsPath = PortletLocalServiceFactory.getImpl().getPortletById(company.getCompanyId(), portletName).getStrutsPath()

So the user can write

<showMore:hello struts_path="view" ...

instead of

<showMore:hello struts_path="/portlet_a/view" ....

hope you can understand my bad english

cheers
Posted on 4/29/08 8:19 AM in reply to Sebastián Gurin.
Posted on 4/29/08 9:29 AM in reply to Sebastián Gurin.
Really nice article! I didn't know about tagfiles! One more thing learned...
Posted on 10/19/10 6:21 AM in reply to Brett Swaim.