Tagfile vs. Tag in a Sling or CQ5 Application

Tagfile vs. Tag in a Sling or CQ5 Application

Custom tags are cool, I guess.  The first couple I wrote were fun to write.  Kind of like driving through a new city, or part of the country.  The landscape is vibrant, new, unfamiliar, exciting.  When I came back several months later, things were just unfamiliar, and not so exciting.

If you are taking the OCEJWCD test, there is no avoiding them.  However, my recommendation is, unless you are writing a Servlet framework, avoid them.  Unless you are writing them with enough frequency to remember the necessary semantics to their creation, the API, it will be a constant battle to remember what all that "stuff" does and means.

Even BEFORE I started using Sling, when still writing POWA (plain old web applications), I started to move away from custom tags to tag files to simplify my maintenance life.  Really, how many times do I really need to re-remember how these things function.  Should I really be making the job of those maintaining the code I wrote more difficult?

Ok, maybe you are like my friend Jeff who has a photographic memory.   I think most of the rest of us don't.  I also don't think the rest of us are developing or maintaining Web Application frameworks which would necessitate the exposure to custom tags, with enough frequency that we remember the semantics and the API.

Also, what about your junior developers?  What if maintenance is contracted out?  What about those capable of maintaining Servlets and JSP's but have no idea what the heck a tag is, other than to use it on a JSP?  Learning stuff is always good.  But I have always favored working with stuff that seems intuitive, and simple.  Tag files fall in that category for me.  Custom tags do not.

OK.  Justifications aside for using tag files instead of tags, here is how you implement these in the context of a Sling or CQ application.

What then, is a tag file?  It is a tag that is implemented as a JSP, requiring a custom tag defined at the head of a JSP.  Here is an example of a King Crimson tag file displaying your favorite KC song:  kcfavsong.tag

<%@tag body-content="empty" isELIgnored="false" display-name="KingCrimson" %>
<%@tag import="java.text.MessageFormat" %>
<%@ attribute name="uname" rtexprvalue="true" required="true" type="java.lang.String" %>
<%@ attribute name="album" rtexprvalue="true" required="true" type="java.lang.String" %>
<%@ attribute name="song" rtexprvalue="true" required="true" type="java.lang.String" %>
<%
String uname = (String) jspContext.getAttribute("uname");
String album = (String) jspContext.getAttribute("album");
String song = (String) jspContext.getAttribute("song");
MessageFormat form = new MessageFormat("{0}'s favorite King Crimson song is\"{2}\" from the Album {1}.");
jspContext.setAttribute("message", form.format( new Object[] {uname, album, song } )  );
%>${message}

You can immediately see that the bar to development, maintenance, and readability has been dramatically lowered.  I will leave it as an example for yourself to develop this as a custom tag.  You tell me which is easier.

In your OSGi bundle project, in the src/main directory you need to create a 'resources' folder, and beneath that create a 'META-INF' folder.  Within META-INF create a text file called: taglib.tld.  Here is a sample tld file for our King Crimson tag file:  taglib.tld

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!--    Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements. See the NOTICE file
   distributed with this work for additional information
   regarding copyright ownership.  The ASF licenses this file
   to you under the Apache License, Version 2.0 (the
   "License"); you may not use this file except in compliance
   with the License.  You may obtain a copy of the License at
   http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an
   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   KIND, either express or implied.  See the License for the
   specific language governing permissions and limitations
   under the License.-->
<taglib 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"
   version="2.0">
   <description>Our Custom Tagfiles</description>
   <tlib-version>1.0</tlib-version>
   <short-name>OurCustomTagfiles</short-name>
   <uri>https://www.yoursite.com/taglibs/cq5/custom/1.0</uri>
   <tag-file>
       <name>kcfavsong</name>
       <path>/META-INF/tags/kcfavsong.tag</path>
   </tag>
</taglib>
Some things to note about this:  description and short-name can be pretty much anything.  They don't really relate to anything in the context of using it within a JSP.  The uri however, matters.  You can see I have chosen a particular structure to convey:  "whose" tag lib it is and what site it's possibly used on (www.yoursite.com), what context it's used within (cq5), a sort of "namespace" in the event you create multiples of tag libraries (custom), and a version number (1.0) to keep track of the currently "released" version.  But in the end, the only REAL reason it matters, is you will be using this URL as the definition of the taglib in your global.jsp for your application, or directly within your JSP's.  The URL can actually be ANYTHING, because it does not relate to schema or anything.

The name portion in the <tag-file> section is the name you will be using to refer to the tag-file when you use it.  More on that in the example usage.  The path is exactly what you think, where it's located.

Beneath the META-INF directory, you will create a 'tags' directory, and put the tag file from above in that directory.

Because I have been implementing this in the same manner using the maven bundle plugin for 4 or 5 years now, I am not completely sure if the following metadata within the definition of the maven bundle plugin, are necessary.  You could try leaving it out and see what happens.  It will either work or it won't.  If it doesn't, put it back in.  If when leaving it out it still works, leave it out.  But I define the following within the <instructions> section of the plugin configuration:

<Bundle-Resource>/META-INF/tags</Bundle-Resource>
<Sling-Bundle-Resource>/META-INF/tags</Sling-Bundle-Resource>

I apologize for this.  It has always just worked this way, so I have never taken the time to attempt to remove any potential redundancy in the configuration of the plugin.  But it does work when defining this metadata.

That is all thats needed from the development side of things.  Now we need to deploy and simply use it.

The usage for this is:

<%@taglib prefix="custom" uri="https://www.yoursite.com/taglibs/cq5/custom/1.0" %>
<custom:kcfavsong uname="mjkelleher" song="SUPERBOTTOMFEEDER" album="Heaven and Earth" />

I recommend you look into the use of: dynamic attributes and scriptless body content.  These will allow you to accomplish much more exotic tag files than what we have produced here.

In a subsequent post, I will build upon this foundation to add a custom EL function to our taglib.  I will show you one particular approach to using a Singleton Facade to manage many custom EL functions in a maintainable manner.

Enjoy.

Share this post

0 Comments

comments powered by Disqus