Explanation
First line is the package statement which tells that DataAccessTag belongs to
com.stardeveloper.tag.test package.
package com.stardeveloper.tag.test;
Then we import the packages whose classes we'll be using in DataAccessTag class.
import java.io.*;
import java.sql.*;
import java.util.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
Then comes our class declaration. This line tells that our class implements BodyTag
interface. final keyword means that this class is final and cannot
be extended. final classes are faster than non-final classes. Making a class final is
*not a requirement* for using in JSP tags.
public final class DataAccessTag implements BodyTag {
Explanation of DataAccessTag Source Code
We then declare six class level variables that we will be using. pc will receive
the PageContext object provided by the JSP page. body will receive the BodyContent
object ( if any ) provided again by the JSP page. sb points to a new StringBuffer
object. We will append Strings to this StringBuffer object when we interate through
the records in the ResultSet. Creating one StringBuffer object is more efficient than
creating serveral String objects.
Then are the three classes used for data access. We save there references in class
level variales so that we can act on them from different methods.
private PageContext pc = null;
private BodyContent body = null;
private StringBuffer sb = new StringBuffer();
private Connection con = null;
private Statement stmt = null;
private ResultSet rs = null;
Now we have to implement all the nine methods of BodyTag interface. Don't worry,
most of the methods are pretty simple. First one is the setPageContext() method. In this
we simply store the reference to PageContext object in our internal class variable; pc.
public void setPageContext(PageContext p) {
pc = p;
}
Then come setParent() and getParent() methods for the parent Tag object. We don't care
about parent Tag so let's keep things simple here.
public void setParent(Tag t) {}
public Tag getParent() { return null; }
Now comes the doStartTag(). Here we connect to "Names" table of a database. We'll
discuss more about the anatomy of this database on the next page. For now just keep in
mind that this database has a table Names with three fields ID, first_name and last_name
respectively. This database has been assigned an ODBC DSN also with the name "NamesDSN" to
keep things simple.
In the doStartTag() we first declare the String objects we'll be using for the path
to the database and the SQL query we want to execute.
Then we connect to the database, create the Statement object, execute this statement
and hopefully get a ResultSet containing retrieved records.
Then we execute another private method of DataAccessTag class called setVariables().
We'll learn more about the code of this method later. For now just keep in mind that
this method set's three scripting variables with names of id, first_name and last_name
available to the JSP page.
We catch any exceptions that might be thrown while executing such code. Possible
return values from doStartTag() method in BodyTag interface are EVAL_BODY_TAG and
SKIP_BODY. EVAL_BODY_TAG causes application server to evaluate the body content of
the tag. While returning SKIP_BODY causes the application server to skip the body
content of this tag.
public int doStartTag() throws JspException {
String path = "jdbc:odbc:NamesDSN";
String sql = "SELECT ID, first_name, last_name FROM Names";
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con = DriverManager.getConnection(path);
stmt = con.createStatement();
rs = stmt.executeQuery(sql);
setVariables();
} catch (SQLException e) {
throw new JspTagException("An SQLException occurred!");
} catch (ClassNotFoundException e) {
throw new JspTagException("JDBC Driver not found.");
}
return EVAL_BODY_TAG;
}
Then comes setBodyContent() in which we save the reference to BodyContent object in
the internal body ( BodyContent ) variable.
public void setBodyContent(BodyContent b) {
body = b;
}
For doInitBody() we end up with an empty implementation, since we
don't need this method in DataAccessTag.
public void doInitBody() throws JspException {}
Then comes our own setVariables() method. This method moves the row pointer in the
ResultSet object one row forward and retrieves the field values from that row and
inserts into the id, first_name and last_name page-level variables of the PageContext
object.
private boolean setVariables() throws JspTagException {
try {
if (rs.next()) {
pc.setAttribute("id", rs.getObject(1).toString());
pc.setAttribute("first_name", rs.getObject(2).toString());
pc.setAttribute("last_name", rs.getObject(3).toString());
return true;
} else {
return false;
}
} catch (SQLException e) {
throw new JspTagException("SQLException occurred!);
}
}
Explanation of DataAccessTag Source Code
We now have doAfterBody(), doEndTag() and release() methods remaining to be
implemented by the DataAccessTag class. Let' see them one by one.
In doAfterBody() we get the body content of the tag using BodyContent object's
getString() method. Then we append this retrieved String object to the StringBuffer
object we created earlier. Once done, we clear the body content.
Next we call setVariables() method again if there are records remaining in the
ResultSet object to be shown. If there are further records remaining in the ResultSet
object then we return EVAL_BODY_TAG which causes body content to be evaluated again.
This time the value of id, first_name and last_name variables is set to new values
retrieved from the database.
When all the records have been shown by looping again and again in the doAfterBody()
method we move forward and write all the records ( which were appended to the StringBuffer
object ) to the client browser and return SKIP_BODY to skip further processing of body
content.
public int doAfterBody() throws JspException {
try {
sb.append(body.getString());
body.clear();
} catch (IOException e) {
throw new JspTagException("Fatal IOException!");
}
if(setVariables()) {
return EVAL_BODY_TAG;
}
try {
body.getEnclosingWriter().write(sb.toString());
} catch (IOException e) {
throw new JspTagException("Fatal IOException!");
}
return SKIP_BODY;
}
In doEndTag() we close ResultSet, Statement and Connection objects we created earlier.
There isn't anything else here.
public int doEndTag() throws JspException {
try {
if(rs != null) {
rs.close();
rs = null;
}
if(stmt != null) {
stmt.close();
stmt = null;
}
if(con != null) {
con.close();
con = null;
}
} catch (SQLException e) {}
return EVAL_PAGE;
}
In the release() method we remove the references we had of PageContext, BodyContent
and StringBuffer objects.
public void release() {
pc = null;
body = null;
sb = null;
}
Database
For use in this tutorial you'll have to create a database in Microsoft Access (
you can use any other database if you want to but for that you'll also have to edit
the JDBC driver name and path to the database variables with the correct ones in the
doStartTag() method ).