/**
MySimpleTag.java
Simple Tag Handler by Sandeep Desai (http://www.thedesai.net/sandeep)
A new instance of SimpleTag is created for every JSP invocation
(instance not reused by contaier unlike classic tags)
JspTag
SimpleTag
SimpleTagSupport
Tag
IterationTag
TagSupport
BodyTagSupport implements BodyTag
interface javax.servlet.jsp.tagext.JspTag
interface javax.servlet.jsp.tagext.SimpleTag extends JspTag
void doTag() throw JspException, IOException
JspTag getParent()
void setJspBody(JspFragment)
void setJspContext(JspContext)
void setParent(JspTag parent)
class SimpleTagSupport implements SimpleTag
JspTag findAncestorWithClass(jspTag, Class)
JspFragment getJspBody()
JspContext getJspContext()
// body of JSP is a JspFragment
// cannot contain scripting elements
// to access body contents implement your own Writer
abstract class JspFragment
invoke(java.io.Writer)
JspContext getJspContext()
abstract class JspContext
getAttribute(name) // find Attribute in page scope
getAttribute(String name, int scope)
Enumeration getAttributeNamesInScope(int scope)
findAttribute(String name)
getOut()
class PageContext extends JspContext
APPLICATION_SCOPE
PAGE_SCOPE
REQUEST_SCOPE
SESSION_SCOPE
getRequest()
getServleConfig()
getServletContext()
getSession()
When JSP calls tag Web Container does following
1) Loads MySimpleTag.class
2) MySimpleTag m = new MySimpleTag()
3) m.setJspContext(JspContext) // reference to pageContext
4) if tag nested calls setParent(JspTag)
5) if tag has attributes call attribute setters in MySimpleTag
6) if body-content not empty in tld call setJspbody(JspFragment)
7) m.doTag()
8) variable syncrhonization ?
Simple Tag Handler <--> Classic Tag Handler differences
interfaces SimpleTag <--> Tag, IterationTag, BodyTag
implementation classes SimpleTagSupport <--> TagSupport, BodyTagSupport
lifecycle methods doTag() <--> doStartTag() doEndTag() doAfterBody()
doInitBody() setBodyContent() // BodyTagSupport
write response getJspContext().getOut().println <-->
pageContext().getOut.().println
process body in doTag() getJspBody.invoke(null) <-->
return EVAL_BODY_INCLUDE in doStartTag()
how to skip body throw new SkipPageException() <--> return SKIP_PAGE in doEndTag()
instance new on each invocation <--> reused across invocation
implement DynamicAttributes interface to support Dynamic attributes
Add <dynamic-attributes> tag to TLD
*/
package foo;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MySimpleTag extends SimpleTagSupport {
public MySimpleTag() { }
public void doTag() throws JspException, IOException {
PageContext tagContext = (PageContext) getJspContext();
HttpServletRequest request = (HttpServletRequest) tagContext.getRequest();
String requestURI = request.getRequestURI();
// handle invocation with no attributes
if (showCars == null) {
getJspContext().getOut().print("Hello from MySimpleTag<br>");
// called from JSP as <my:simple> Print ${fooAttrib} </my:simple>
getJspContext().setAttribute("fooAttrib" , "barValue");
// if has body is scriptless in tld
// Code throws Null pointer Exception if body not provided
getJspBody().invoke(null); // null means do out.write()
}
// handle invocation with showCars atribute and body with ${car}
// We are invoking the body multiple times with different attribute values
if (showCars != null && showCars.equalsIgnoreCase("basic")) {
for (int i = 0; i < cars.length; ++i) {
getJspContext().setAttribute("car", cars[i]);
getJspBody().invoke(null);
getJspContext().getOut().print(",");
}
}
// handle invocatin where we get the list in an attribute
// and body has ${car} and we invoke body multiple times
if (showCars != null && showCars.equalsIgnoreCase("luxury")) {
for (Iterator it = carList.iterator(); it.hasNext();) {
String car = (String) it.next();
getJspContext().setAttribute("car", car);
getJspBody().invoke(null);
getJspContext().getOut().print(",");
}
}
// throw SkipPageException for an invalid value
if (showCars != null && showCars.equalsIgnoreCase("antiques")) {
getJspContext().getOut().print("Incorrect value antiques, throwing SkipPageException");
// SkipPageException will prevent rest of the JSP page from being displayed
// If thrown in included file will allow the caller page to be displayed
// only included pages is not displayed completely
throw new SkipPageException();
}
// Nested Tags, (Simple Tag can have Classic Tag as parent)
// Note there's no getChild() so implementor has to keep track of children
if (false) {
//OuterTag tag = (OuterTag)getParent();
//JspTag parentTag = getParent();
//while (parentTag != null) {
// parentTag = parentTag.getParent();
//}
// find arbitary ancestor
//SomeOuterTag ancestor = findAncestorWithClass(this, SomeOuterTag.class);
}
}
public void setShowCars(String showCars) {
this.showCars = showCars;
}
public void setCarList(List carList) {
this.carList = carList;
}
private String showCars;
private String[] cars = {"Honda Accord", "Toyota Camry" };
private List carList;
}