|
<taglib:tutorial lesson="16"/>
In this part of the tutorial, we will look at how a fragment of a JSP page can be passed to a SimpleTag as an attribute
1 Lesson 16, Fragments as attributes
In this part of the tutorial we will look closer at the JspFragment as an attribute type and how this can be utilized by SimpleTags to allow JSP fragments to be given to the Simple Tag handler without resolving to using a Tag body.
We will continue to use the setup previously defined for this tutorial.
During this lesson, you will implement a SimpleTag that will accept fragments of JSP as attributes and then write a view that can be used to try it out.
2 What is a JspFragment?
3 Creating the SimpleIteratorTag
To demonstrate how JspFragments can be passed in as attribute we are going to write yet another Iterator, but this time the page author will be given the option to process the entries differently depending upon if the current count is even or odd, as well as specifying header, footer and processing of empty collections.
 Figure 2. The SimpleIteratorTag
The emptyJspFragment will, if specified, be evaluated instead of the SimpleBodys body if the collection attribute holds an empty Collection or null.
The oddJspFragment will, if specified, be evalutated instead of the SimpleBodys body every other iteration (when the current count is an odd number).
The evenJspFragment will, if specified, behave just like the odd attribute but when the current count is an even number.
The header and footerJspFragments will, if specified, be evaluated before (header) or after (footer) the non empty collection is itterated.
The actual logic will be a number of conditional checks where one or the other of the JspFragments will be invoked depending upon the outcome. The passed in JspFragments are treated just as the body of the SimpleTag, as will become obvious when looking at the actual implementation.
-
In the '/WEB-INF/classes/com/acme/tag/' directory, create a new class called 'SimpleIteratorTag.java' with the following content:
package com.acme.tag;
import javax.servlet.jsp.tagext.SimpleTagSupport; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.JspException; import java.util.Collection; import java.util.Iterator; import java.io.IOException;
public class SimpleIteratorTag extends SimpleTagSupport { private Collection collection; private JspFragment header; private JspFragment footer; private JspFragment empty; private JspFragment even; private JspFragment odd; private String type; private String id; private String counter;
|
Listing 1: The start of the SimpleIteratorTag
In the listing above, we define the variables that our SimpleTag will need, of which most will be used as attribute fields.
-
Continue by adding accessor methods for these fields as in the listing below:
public SimpleIteratorTag(){}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getCounter() { return counter; }
public void setCounter(String counter) { this.counter = counter; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public Collection getCollection() { return collection; }
public void setCollection(Collection collection) { this.collection = collection; }
public JspFragment getHeader() { return header; }
public void setHeader(JspFragment header) { this.header = header; }
public JspFragment getFooter() { return footer; }
public void setFooter(JspFragment footer) { this.footer = footer; }
public JspFragment getEmpty() { return empty; }
public void setEmpty(JspFragment empty) { this.empty = empty; }
public JspFragment getEven() { return even; }
public void setEven(JspFragment even) { this.even = even; }
public JspFragment getOdd() { return odd; }
public void setOdd(JspFragment odd) { this.odd = odd; }
|
Listing 2: A constructor and a bunch of accessors
-
Now its time to add the doTag method that will hold all the conditional and iterative operations that our SimpleTag will require. Add the following:
public void doTag() throws JspException, IOException { if(getCollection()!=null && getCollection().size()>0) { if(header!=null) header.invoke(null);
|
Listing 3: If the Collection contains items any specified header fragments should be invoked.
In the listing above, we check if the Collection contains any items. If so, we invoke any specified headerJspFragment.
-
Continue with the following:
Iterator items=getCollection().iterator(); int count=0; while(items.hasNext()) { count++; this.getJspContext().setAttribute(id,items.next()); if(counter!=null) this.getJspContext().setAttribute(counter,new Integer(count));
|
Listing 4: Iterating through the items of the Collection.
Above, we create an Iterator on the collection that we then iterate through. For each iteration, we add the current item to the JspContext of the SimpleTag with the name specified in the id attribute, which will be shared by the various JspFragments involved.
If a counter attribute has been specified, we also add the current iteration count to the JspContext of the SimpleTag using the name specified in the counter attribute.
-
Continue with the following:
if(count%2==0 && even!=null) even.invoke(null); else if (count%2!=0 && odd!=null) odd.invoke(null); else this.getJspBody().invoke(null); }
|
Listing 5: Calculating which fragments to invoke
In the code section above we invoke the even fragment on every even iteration count and the odd one on every odd count, provided that these attributes has been specified, otherwize the normal body of the SimpleTag will be invoked.
-
Continue with the following:
if(footer!=null) footer.invoke(null);
|
Listing 6: If the Collection contained items any specified footer fragment should be invoked.
In the listing above, we invoke the footerJspFragment if the Collection wasn't emtpy.
-
End the SimpleTag with the following code:
} else { if(empty!=null) empty.invoke(null); } } }
|
Listing 7: Handle empty Collection and end the class
In the code section above we invoke the emtpyJspFragment if this attribute has been specified and the specified collection Collection held no items.
|
By now, your SimpleIteratorTag.java should look like this. Store the sourcecode in the /WEB-INF/classes/com/acme/tag/ directory as SimpleIteratorTag.java
|
-
Compile the SimpleTag. If needed, details are given here. The result should be a file named SimpleIteratorTag.class in the /WEB-INF/classes/com/acme/tag/ directory.
4 Creating the SimpleIteratorTEI
As our SimpleTag will be adding objects of unknown types to the JspContext we need to provide our SimpleTag with a accompanying TEI class. If you have already gone through lesson 10 you will notice that this TEI will be very similar to the IteratorTEI we developed then.
As this is our first TEI for JSP 2.0, it is worth mentioning that the Expression Language of JSP 2.0 does not require attributes to be addes as scripting variables to the JSP pages in order to find and use them, while standard actions and custom handlers (tags) still does.
 Figure 3. The SimpleIteratorTEI
The major difference between the TEI developed in lesson 10 and this one will be that this TEI will define two scripting variables, namely:
id - the name the iterated item will be added to the PAGE_SCOPE as. The type will be retrieved from the type attribute which we can get at thorugh the TagData, just as with the id attribute.
counter - the name the iteration counter will be added to the PAGE_SCOPE as.
-
In the '/WEB-INF/classes/com/acme/tag/' directory, create a new class called 'SimpleIteratorTEI.java' with the following content:
package com.acme.tag;
import javax.servlet.jsp.tagext.VariableInfo; import javax.servlet.jsp.tagext.TagData; import javax.servlet.jsp.tagext.TagExtraInfo;
public class SimpleIteratorTEI extends TagExtraInfo {
public SimpleIteratorTEI() { super(); }
public VariableInfo[] getVariableInfo(TagData data) { return new VariableInfo[] { new VariableInfo( data.getAttributeString("id"), data.getAttributeString("type"), true, VariableInfo.NESTED ),
|
Listing 8: The SimpleIteratorTEI
Above, we use the TagData object to retrieve the value of the id and type attributes that was passed into the SimpleIteratorTag. We also tell the Container to treat the added variable as if it was a new variable, and that the variable should be available from the start of the SimpleTag to the end.
-
Continue with the following:
new VariableInfo( data.getAttributeString("counter"), data.getAttributeString("java.lang.Integer"), true, VariableInfo.NESTED ) }; } }
|
Listing 9: the SimpleIteratorTEI continued
Above, we declare a second VariableInfo that uses the TagData object to retrieve the value of the counter attribute as the name of the variable that is of the type java.lang.Integer and that the added variable should be a new variable that should be available from the start of the SimpleTag to the end.
|
Your SimpleIteratorTEI.java should look like this. Store the sourcecode in the /WEB-INF/classes/com/acme/tag/ directory as SimpleIteratorTEI.java
|
-
Compile the TEI-class. If needed, details are given here. The result should be a file named SimpleIteratorTEI.class in the /WEB-INF/classes/com/acme/tag/ directory.
5 Update the Tag Library Descriptor
We should now describe our new Tag together with its accompanying TEI in the Tag library descriptor we created in lesson 15.
-
Open your 'taglib2.0.tld' from your '/WEB-INF' directory with your favourite editor.
-
Edit the TagLibrary descriptor and add the SimpleIteratorTag as in listing 6 below.
<tag> <name>iterate</name> <tag-class>com.acme.tag.SimpleIteratorTag</tag-class> <tei-class>com.acme.tag.SimpleIteratorTEI</tei-class> <body-content>scriptless</body-content> <attribute> <name>id</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>type</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>collection</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.util.Collection</type> </attribute> <attribute> <name>counter</name> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>header</name> <fragment>true</fragment> </attribute> <attribute> <name>footer</name> <fragment>true</fragment> </attribute> <attribute> <name>even</name> <fragment>true</fragment> </attribute> <attribute> <name>odd</name> <fragment>true</fragment> </attribute> </tag>
|
Listing 9: The modified Taglibrary descriptor.
Notice the lack of the counter variable in the tag descriptor above. Although this Integer would make an excellent example of using the variable declaration in the TLD, the specification forbids us to have both TEI classes that returns a VariableInfo[] of a size larger than zero and having a variable-element in the TLD. For more information about the variable tag, see lesson 12.
Also notice that body-content cannot be set to JSP as SimpleTags cannot contain Scriptlets.

|
By now, your taglib2.0.tld should look like this. Store the descriptor in the /WEB-INF/ directory as taglib2.0.tld.
|
6 Creating some Beans
If you haven't already gone through lesson 10, you should now do so now as we will reuse the beans created there (though initially created in lesson 5.
You can get the source for the Company bean here, and the source for the Contact bean is here.
Make sure that you compile the beans and put them in your '/WEB-INF/classes/com/acme/bean/' directory if you haven't got them there already.
7 Presenting the new Tag
8 Using your new Tag
We are now ready to use your new Tag.
|
Open the URL
http://localhost/taglib/odd.jsp in a normal web browser. Hopefully the result looks like
this.
|
Continue with lesson 17", "Attributes with dynamic names".
Copyright ©
2005 IronFlare AB
|