Writing Pesticide Using XslServletPesticide, the bug tracker application, demonstrates XslServlet in its two servlets, BugList and BugForm . Writing BugListThe first XslServlet is BugList , which prints the list of bugs (see Listing 8.4). Listing 8.4 BugList.javapackage com.psol.pesticide; import java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; public class BugList extends XslServlet { public void init() throws ServletException { try { Class.forName(getInitParameter("driver")); } catch(ClassNotFoundException e) { throw new ServletException(e); } } protected void writeBugList(Connection conn, String pid, String sid, XslWriter writer) throws SQLException, IOException { StringBuffer query = new StringBuffer("select " + "bug.id, bug.name, solved, created, software.name " + " from bug inner join software on " + "bug.softwareid=software.id"); boolean isPid = null != pid && 0 != pid.length(), isSid = null != sid && 0 != sid.length(); if(isPid) query.append(" where bug.programmerid=?"); if(isSid) if(isPid) query.append(" and bug.softwareid=?"); else query.append(" where bug.softwareid=?"); query.append(" order by solved, created"); PreparedStatement stmt = conn.prepareStatement(query.toString()); try { if(isPid) stmt.setString(1,pid); if(isSid) if(isPid) stmt.setString(2,sid); else stmt.setString(1,sid); ResultSet rs = stmt.executeQuery(); try { writer.write("<bug-list>"); String[] fields = { "id", "name", "solved", "created", "software-name" } ; while(rs.next()) SQLUtil.writeRow("bug",fields,rs,writer); writer.write("</bug-list>"); } finally { rs.close(); } } finally { stmt.close(); } } public void doGet(HttpServletRequest request, HttpServletResponse response, XslServletLiaison liaison) throws IOException, ServletException { try { String url = getInitParameter("url"), username = getInitParameter("username"), password = getInitParameter("password"); Connection conn = DriverManager.getConnection(url,username,password); XslWriter writer = liaison.getWriter(); writer.write("<page>"); try { String pid = request.getParameter("programmerid"), sid = request.getParameter("softwareid"); if(null != pid) pid = pid.trim(); if(null != sid) sid = sid.trim(); writeBugList(conn,pid,sid,writer); SQLUtil.writeProgrammerList(conn,pid,writer); SQLUtil.writeSoftwareList(conn,sid,writer); } finally { conn.close(); } writer.write("</page>"); } catch(SQLException e) { throw new ServletException(e); } catch(Exception e) { throw new ServletException(e); } } } Warning For simplicity, the servlet does not maintain a pool of database connections. Although this is not a problem with Hypersonic SQL (see the section Building and Running the Project later in this chapter), it might negatively impact performances with other databases. BugList is very similar to a regular servlet. It connects to the database, extracts information, and writes the result. The only remarkable aspect is that it overrides your version of doGet() and writes the result in presentation-neutral XML. Some of the database code is shared between BugList and BugForm . It has been moved to SQLUtil (see Listing 8.5). Tip You might wonder why the servlet uses a PreparedStatement , even though it runs the statement only once. Briefly, it simplifies parameter processing because it is possible to use the setString() methods . Listing 8.5 SQLUtil.javapackage com.psol.pesticide; import java.io.*; import java.sql.*; public class SQLUtil { public static void writeFields(String[] fields, ResultSet rs, XslWriter writer) throws SQLException, IOException { for(int i = 0;i < fields.length;i++) { String value = rs.getString(i + 1); writer.write('<'); writer.write(fields[i]); writer.write('>'); if(!rs.wasNull()) writer.escape(value); writer.write("</"); writer.write(fields[i]); writer.write('>'); } } public static void writeRow(String name, String[] fields, ResultSet rs, XslWriter writer) throws SQLException, IOException { writeRow(name,null,null,fields,rs,writer); } public static void writeRow(String name, String id, String attribute, String[] fields, ResultSet rs, XslWriter writer) throws SQLException, IOException { writer.write('<'); writer.write(name); if(null != attribute) { String value = rs.getString(1); if(id != null && id.equals(value)) { writer.write(''); writer.write(attribute); } } writer.write('>'); writeFields(fields,rs,writer); writer.write("</"); writer.write(name); writer.write('>'); } public static void writeSoftwareList(Connection conn, String id, XslWriter writer) throws SQLException, IOException { Statement stmt = conn.createStatement(); try { ResultSet rs = stmt.executeQuery("select id, " + "name from software order by name"); try { String[] fields = { "id", "name" } ; writer.write("<software-list>"); while(rs.next()) writeRow("software",id,"selected='yes'", fields,rs,writer); writer.write("</software-list>"); } finally { rs.close(); } } finally { stmt.close(); } } public static void writeProgrammerList(Connection conn, String id, XslWriter writer) throws SQLException, IOException { Statement stmt = conn.createStatement(); try { ResultSet rs = stmt.executeQuery("select id, " + "name from programmer order by name"); try { String[] fields = { "id", "name" } ; writer.write("<programmer-list>"); while(rs.next()) writeRow("programmer",id,"selected='yes'", fields,rs,writer); writer.write("</programmer-list>"); } finally { rs.close(); } } finally { stmt.close(); } } } The BugList Style SheetObviously, BugList needs a style sheet, such as that shown in Listing 8.6. Note that the complete filename for this file is fast/com/psol/pesticide/BugList.xsl for the fast skin. The style sheet should be familiar; it turns a list of bugs into a nicely formatted HTML page. In a browser, it looks similar to Figure 8.3. Figure 8.3. The servlet with the fast skin.
Listing 8.6 BugList.xsl (cool version)<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/REC-html40" version="1.0"> <xsl:output method="html" encoding="ISO-8859-1"/> <xsl:template match="/"> <HTML> <HEAD><TITLE>Bugs List</TITLE></HEAD> <BODY> <xsl:apply-templates/> <A HREF="/buglist/cool">Graphics</A> </BODY> </HTML> </xsl:template> <xsl:template match="page"> <FORM METHOD="GET" ACTION="/buglist/fast"> <SELECT NAME="programmerid"> <OPTION VALUE="">All programmers</OPTION> <xsl:apply-templates select="programmer-list"/> </SELECT> <SELECT NAME="softwareid"> <OPTION VALUE="">All applications</OPTION> <xsl:apply-templates select="software-list"/> </SELECT> <INPUT TYPE="SUBMIT" VALUE="Go"/> </FORM> <xsl:apply-templates select="bug-list"/> </xsl:template> <xsl:template match="software programmer"> <OPTION> <xsl:attribute name="VALUE"> <xsl:apply-templates select="id"/> </xsl:attribute> <xsl:apply-templates select="name"/> </OPTION> </xsl:template> <xsl:template match="software[@selected='yes'] programmer[@selected='yes']"> <OPTION SELECTED="SELECTED"> <xsl:attribute name="VALUE"> <xsl:apply-templates select="id"/> </xsl:attribute> <xsl:apply-templates select="name"/> </OPTION> </xsl:template> <xsl:template match="bug-list"> <TABLE> <TR> <TD VALIGN="TOP"><TT>[ ]</TT></TD> <TD><SMALL> <B><A HREF="/bugform/fast">New bug</A></B><BR/> Report a new bug.</SMALL></TD> <TD></TD> </TR> <xsl:apply-templates/> </TABLE> </xsl:template> <xsl:template match="bug"> <TR> <TD VALIGN="TOP"><xsl:choose> <xsl:when test="solved='true'"><TT>[X]</TT></xsl:when> <xsl:otherwise><TT>[ ]</TT></xsl:otherwise> </xsl:choose></TD> <TD><SMALL> <B><A> <xsl:attribute name="HREF"> <xsl:text>/bugform/fast?id=</xsl:text> <xsl:value-of select="id"/> </xsl:attribute> <xsl:apply-templates select="name"/></A> </B><BR/> <xsl:apply-templates select="software-name"/> <xsl:text> @ </xsl:text> <xsl:apply-templates select="created"/></SMALL> </TD> </TR> </xsl:template> </xsl:stylesheet> Writing BugFormListing 8.7 illustrates BugForm , the servlet used to edit a bug. Again, the servlet is not remarkable but for its use of XML. Listing 8.7 BugForm.javapackage com.psol.pesticide; import java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; public class BugForm extends XslServlet { public void init() throws ServletException { try { Class.forName(getInitParameter("driver")); } catch(ClassNotFoundException e) { throw new ServletException(e); } } protected void writeEmptyForm(Connection conn, XslWriter writer) throws SQLException, IOException { writer.write("<bug><id/><name/><created/>"); writer.write("<description/><solution/><solved/>"); SQLUtil.writeProgrammerList(conn,null,writer); SQLUtil.writeSoftwareList(conn,null,writer); writer.write("</bug>"); } protected void writeNonEmptyForm(Connection conn, String id, XslWriter writer) throws SQLException, IOException { PreparedStatement stmt = conn.prepareStatement("select " + "id, name, created, description, solution, solved, " + "programmerid, softwareid from bug where id=?"); try { stmt.setString(1,id); ResultSet rs = stmt.executeQuery(); try { writer.write("<bug>"); if(rs.next()) { String[] fields = { "id", "name", "created", "description", "solution", "solved" } ; SQLUtil.writeFields(fields,rs,writer); SQLUtil.writeProgrammerList(conn, rs.getString(7), writer); SQLUtil.writeSoftwareList(conn, rs.getString(8), writer); } writer.write("</bug>"); } finally { rs.close(); } } finally { stmt.close(); } } protected void setValue(PreparedStatement stmt, int pos, String value, int type) throws SQLException { if(null == value) stmt.setNull(pos,type); else stmt.setString(pos,value); } protected void writePage(Connection conn, String id, HttpServletRequest request, HttpServletResponse response, XslServletLiaison liaison) throws IOException, SQLException { XslWriter writer = liaison.getWriter(); writer.write("<page>"); if(null != id && 0 != id.length()) writeNonEmptyForm(conn,id,writer); else writeEmptyForm(conn,writer); writer.write("</page>"); } protected String updateBug(Connection conn, String id, HttpServletRequest request) throws SQLException { PreparedStatement stmt = null; if(null != id && 0 != id.length()) stmt = conn.prepareStatement("update bug set name=?," + " created=?, description=?, solution=?, solved=?," + " programmerid=?, softwareid=? where id=?"); else stmt = conn.prepareStatement("insert into bug (name, " + "created, description, solution, solved, " + "programmerid, softwareid) values (?,?,?,?,?,?,?)"); try { setValue(stmt,1,request.getParameter("name"), Types.VARCHAR); setValue(stmt,2,request.getParameter("created"), Types.DATE); setValue(stmt,3,request.getParameter("description"), Types.VARCHAR); setValue(stmt,4,request.getParameter("solution"), Types.VARCHAR); setValue(stmt,5,request.getParameter("solved"), Types.BIT); setValue(stmt,6,request.getParameter("programmerid"), Types.INTEGER); setValue(stmt,7,request.getParameter("softwareid"), Types.INTEGER); if(null != id && 0 != id.length()) stmt.setString(8,id); stmt.executeUpdate(); if(null == id 0 == id.length()) { Statement s = conn.createStatement(); try { ResultSet rs = s.executeQuery( "select max(id) from bug"); try { if(rs.next()) id = rs.getString(1); } finally { rs.close(); } } finally { s.close(); } } } finally { stmt.close(); } return id; } public void doGet(HttpServletRequest request, HttpServletResponse response, XslServletLiaison liaison) throws IOException, ServletException { try { String url = getInitParameter("url"), username = getInitParameter("username"), password = getInitParameter("password"); Connection conn = DriverManager.getConnection(url,username,password); try { String id = request.getParameter("id"); if(null != id) id = id.trim(); writePage(conn,id,request,response,liaison); } finally { conn.close(); } } catch(SQLException e) { throw new ServletException(e); } } public void doPost(HttpServletRequest request, HttpServletResponse response, XslServletLiaison liaison) throws IOException, ServletException { try { String url = getInitParameter("url"), username = getInitParameter("username"), password = getInitParameter("password"); Connection conn = DriverManager.getConnection(url,username,password); try { String id = request.getParameter("id"); if(null != id) id = id.trim(); id = updateBug(conn,id,request); writePage(conn,id,request,response,liaison); } finally { conn.close(); } } catch(SQLException e) { throw new ServletException(e); } } } You should notice writeEmptyForm() , which writes an empty XML document. The style sheet needs an empty XML document to produce an empty HTML form: protected void writeEmptyForm(Connection conn, XslWriter writer) throws SQLException, IOException { writer.write("<bug><id/><name/><created/>"); writer.write("<description/><solution/><solved/>"); SQLUtil.writeProgrammerList(conn,null,writer); SQLUtil.writeSoftwareList(conn,null,writer); writer.write("</bug>"); } The BugForm Style SheetListing 8.8 is the style sheet for BugForm , using the fast skin. Listing 8.8 BugForm.xsl (fast version)<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/REC-html40" version="1.0"> <xsl:output method="html" encoding="ISO-8859-1"/> <xsl:template match="/"> <HTML> <HEAD><TITLE>Edit a Bug</TITLE></HEAD> <BODY> <xsl:apply-templates/> <A HREF="/buglist/cool">Graphics</A> </BODY> </HTML> </xsl:template> <xsl:template match="page"> <FORM ACTION="/buglist/fast" METHOD="GET"> <SELECT NAME="programmerid"> <OPTION VALUE="">All programmers</OPTION> <xsl:apply-templates select="bug/programmer-list" mode="menu"/> </SELECT> <SELECT NAME="softwareid"> <OPTION VALUE="">All applications</OPTION> <xsl:apply-templates select="bug/software-list" mode="menu"/> </SELECT> <INPUT TYPE="SUBMIT" VALUE="Go"/> </FORM> <xsl:apply-templates select="bug"/> </xsl:template> <xsl:template match="software programmer" mode="menu"> <OPTION> <xsl:attribute name="VALUE"> <xsl:value-of select="id"/> </xsl:attribute> <xsl:apply-templates select="name"/> </OPTION> </xsl:template> <xsl:template match="software[@selected='yes'] programmer[@selected='yes']" mode="menu"> <OPTION SELECTED="SELECTED"> <xsl:attribute name="VALUE"> <xsl:value-of select="id"/> </xsl:attribute> <xsl:apply-templates select="name"/> </OPTION> </xsl:template> <xsl:template match="bug"> <xsl:choose> <xsl:when test="count(child::*) = 0"> <P><B>Empty!</B></P> </xsl:when> <xsl:otherwise> <FORM ACTION="/bugform/fast" METHOD="POST"> <TABLE> <xsl:apply-templates/> <TR><TD> <INPUT TYPE="SUBMIT" VALUE="Save"/> </TD></TR> </TABLE> </FORM> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="bug/id"> <INPUT TYPE="HIDDEN" NAME="id"> <xsl:attribute name="VALUE"> <xsl:value-of select="."/> </xsl:attribute> </INPUT> </xsl:template> <xsl:template match="bug/name"> <TR> <TD VALIGN="TOP"><SMALL>Name:</SMALL></TD> <TD><INPUT NAME="name"> <xsl:attribute name="VALUE"> <xsl:value-of select="."/> </xsl:attribute> </INPUT></TD> </TR> </xsl:template> <xsl:template match="created"> <TR> <TD VALIGN="TOP"><SMALL>Created:</SMALL></TD> <TD><INPUT NAME="created"> <xsl:attribute name="VALUE"> <xsl:value-of select="."/> </xsl:attribute> </INPUT><SMALL> (yyyy-mm-dd)</SMALL></TD> </TR> </xsl:template> <xsl:template match="description"> <TR> <TD VALIGN="TOP"><SMALL>Description:</SMALL></TD> <TD><TEXTAREA NAME="description"> <xsl:value-of select="."/> </TEXTAREA></TD> </TR> </xsl:template> <xsl:template match="solved"> <TR> <TD VALIGN="TOP"><SMALL>Status:</SMALL></TD> <TD><SELECT NAME="solved"> <xsl:choose> <xsl:when test="text()='true'"> <OPTION VALUE="TRUE" SELECTED="SELECTED">Resolved</OPTION> <OPTION VALUE="FALSE">Unresolved</OPTION> </xsl:when> <xsl:otherwise> <OPTION VALUE="TRUE">Resolved</OPTION> <OPTION VALUE="FALSE" SELECTED="SELECTED">Unresolved</OPTION> </xsl:otherwise> </xsl:choose> </SELECT></TD> </TR> </xsl:template> <xsl:template match="solution"> <TR> <TD VALIGN="TOP"><SMALL>Solution:</SMALL></TD> <TD><TEXTAREA NAME="solution"> <xsl:value-of select="."/> </TEXTAREA></TD> </TR> </xsl:template> <xsl:template match="programmer-list"> <TR> <TD VALIGN="TOP"><SMALL>Programmer:</SMALL></TD> <TD><SELECT NAME="programmerid"> <xsl:apply-templates/> </SELECT></TD> </TR> </xsl:template> <xsl:template match="software-list"> <TR> <TD VALIGN="TOP"><SMALL>Application:</SMALL></TD> <TD><SELECT NAME="softwareid"> <xsl:apply-templates/> </SELECT></TD> </TR> </xsl:template> <xsl:template match="software programmer"> <OPTION> <xsl:attribute name="VALUE"> <xsl:value-of select="id"/> </xsl:attribute> <xsl:apply-templates select="name"/> </OPTION> </xsl:template> <xsl:template match="software[@selected='yes'] programmer[@selected='yes']"> <OPTION SELECTED="SELECTED"> <xsl:attribute name="VALUE"> <xsl:value-of select="id"/> </xsl:attribute> <xsl:apply-templates select="name"/> </OPTION> </xsl:template> </xsl:stylesheet> |