14.6 A Tool Application

Java Servlet Programming, 2nd Edition > 14. The Tea Framework > 14.6 A Tool Application

 
< BACKCONTINUE >

14.6 A Tool Application

Determining a user's name is hardly a realistic application, so let's continue now with something closer. We'll create an application that displays a list of the various content creation tools available (an application much like what Servlets.com requires). The tool information will come from an XML file, although it could just as well come from a database. Example 14-8 shows the ToolApp class.

Example 14-8. The Brains of a Tool Application
import com.go.teaservlet.*; import com.go.trove.log.*; import java.sql.Timestamp; import java.util.*; import javax.servlet.*; public class ToolApp implements Application {   private Log log;   private Tool[] tools;   public void init(ApplicationConfig config) throws ServletException {     // Keep a log of events specific to this application     log = config.getLog();     // Load the tool data in our init for simplicity     String toolsFile = config.getInitParameter("toolsFile");     if (toolsFile == null) {       throw new ServletException(         "A tools data file must be specified as the toolsFile init parameter");     }     log.debug("Loading tools from " + toolsFile);     try {       tools = Tool.loadTools(toolsFile);       if (tools.length == 0) {         log.warn("No tools found in " + toolsFile);       }     }     catch (Exception e) {       log.error(e);       throw new ServletException(e);     }   }   public Object createContext(ApplicationRequest request,                               ApplicationResponse response) {     return new ToolContext(request, response, this);   }   public Class getContextType() {     return ToolContext.class;   }   public void destroy() {   }   public Tool[] getTools() {     // Normally the "application" would maintain or have access to a      // pre-existing database connection.  Here, for simplicity, we use XML.     return tools;   }   public Tool[] getTools(String state) {     // Return only tools of a given state     // (submitted, live, rejected, or dead)     List list = new LinkedList();     for (int i = 0; i < tools.length; i++) {       if (tools[i].getStateFlag().equalsIgnoreCase(state)) {         list.add(tools[i]);       }     }     return (Tool[]) list.toArray(new Tool[0]);   } }

The init( ) method of ToolApp uses the passed-in ApplicationConfig to retrieve and save a reference to the log, then uses the config to get the value of the init parameter toolsFile. This parameter value must be specified in the TeaServlet.properties file:

"ToolApp" {     class = ToolApp     init {         toolsFile = /tomcat/webapps/teatime/WEB-INF/tools.xml     } }

The init( ) method then calls loadTools( ) to load the tool information from the XML file into the tools array. The XML file should look something like Example 14-9.

Example 14-9. Sample Data
<?xml version="1.0"?> <tools>   <tool >     <name>JavaServer Pages</name>     <homeURL>http://java.sun.com/products/jsp</homeURL>     <comments>       JavaServer Pages (JSP) is a technology created by Sun Microsystems        and closely tied to servlets.  As with servlets, Sun releases a JSP        specification, and third-party vendors compete on their implementation        of that standard.  Being released by Sun puts JSPs in a very privileged        position, and had JSP solved a sufficient number of user problems it        would probably have won the market before there were any other viable        entries.  As is, a surprising number of users are disenchanted with JSP        and alternatives are gaining popularity.     </comments>     <stateFlag>LIVE</stateFlag>     <createdTime>1998-03-17 00:00:00.000</createdTime>     <modifiedTime>1999-12-16 00:00:00.000</modifiedTime>   </tool>   <tool >     <name>Tea</name>     <homeURL>http://opensource.go.com</homeURL>     <comments>       Tea is a newly open sourced product from the Walt Disney Internet Group,       created internally over the years to solve their tremendous web production       needs for sites such as ESPN.com.  It's similar to JSP although it avoids        many of JSPs problems, and already has terrific tools support.     </comments>     <stateFlag>LIVE</stateFlag>     <createdTime>2000-07-12 00:00:00.000</createdTime>     <modifiedTime>2000-07-12 00:00:00.000</modifiedTime>   </tool>   <tool >     <name>WebMacro</name>     <homeURL>http://jakarta.apache.org</homeURL>     <comments>       WebMacro is a template engine created by Semiotek as part of the Shimari       project and now merged into the Apache Jakarta Project.  WebMacro has        been used on commercial sites such as AltaVista.com, has been integrated        in open source frameworks such as Turbine and Melati, and has been used        in prominent open source projects such as JetSpeed.     </comments>     <stateFlag>LIVE</stateFlag>     <createdTime>1998-11-19 00:00:00.000</createdTime>     <modifiedTime>2000-08-31 00:00:00.000</modifiedTime>   </tool>   <tool >     <name>Element Construction Set</name>     <homeURL>http://java.apache.org/ecs</homeURL>     <comments>       The Element Construction Set (ECS) package from the Java Apache Project       is a set of classes modeled after the htmlKona product from WebLogic        (now BEA Systems).  ECS has many limitations, but it solves a certain        class of problems.     </comments>     <stateFlag>LIVE</stateFlag>     <createdTime>1999-03-31 00:00:00.000</createdTime>     <modifiedTime>2000-06-16 00:00:00.000</modifiedTime>   </tool>   <tool >     <name>XMLC</name>     <homeURL>http://xmlc.enhydra.org</homeURL>     <comments>       XMLC makes use of XML to get nearly all the power of ECS without many of       its limitations.  It was created by Lutris as part of their Open Source        Enhydra Application Server, and can be used as a separate component.     </comments>     <stateFlag>LIVE</stateFlag>     <createdTime>1998-10-11 00:00:00.000</createdTime>     <modifiedTime>2000-03-09 00:00:00.000</modifiedTime>   </tool>   <!-- etc --> </tools>

The app reads this file using the JDOM API, an open source API for reading, writing, and manipulating XML from Java. If we wanted to read the results from a database instead, we could do this by simply replacing the JDOM SAXBuilder (which builds a Document from a file or stream using a SAX parser) with a JDOM ResultSetBuilder (which builds a Document from a java.sql.ResultSet, a contributed class to JDOM).[3]

[3] Jason is one of the co-creators of JDOM, along with Brett McLaughlin. More information on JDOM can be found at http://jdom.org.

At the time of this writing, JDOM was still under development. This example uses JDOM Beta 5. Some minor changes may be required to work with the final JDOM release.

The createContext( ) method constructs a new ToolContext instance. The code for ToolContext is shown in Example 14-10.

Example 14-10. The Context Containing All Accessible Functions
import com.go.teaservlet.*; public class ToolContext {   ApplicationRequest request;   ApplicationResponse response;   ToolApp app;   public ToolContext(ApplicationRequest request,                      ApplicationResponse response,                      ToolApp app) {     this.request = request;     this.response = response;     this.app = app;   }   public Tool[] getTools() {     return app.getTools();   }   public Tool[] getTools(String state) {     return app.getTools(state);   } }

The public methods on the context are the functions made available to Tea templates. Here the methods call back to the application, something considered good style because contexts should be as lightweight as possible; state should be held in the application. The Tool class itself acts as a holder of Tool information. Example 14-11 shows its code.

Example 14-11. A Class to Load and Hold Tool Data
import java.io.*; import java.sql.*; import java.util.*; import org.jdom.*; import org.jdom.input.*; public class Tool {   // Data about this tool record   public int id;   public String name;   public String homeURL;   public String comments;   public String stateFlag;   public Timestamp createdTime;   public Timestamp modifiedTime;   // Tea can only access bean properties, so accessor methods are required   public int getId() { return id; }   public String getName() { return name; }   public String getHomeURL() { return homeURL; }   public String getComments() { return comments; }   public String getStateFlag() { return stateFlag; }   public Timestamp getCreatedTime() { return createdTime; }   public Timestamp getModifiedTime() { return modifiedTime; }   public int getCreatedAgeInDays() {     return (int) ((System.currentTimeMillis() - createdTime.getTime()) /             (24 * 60 * 60 * 1000));  // millis in a day   }   public int getModifiedAgeInDays() {     return (int) ((System.currentTimeMillis() - modifiedTime.getTime()) /             (24 * 60 * 60 * 1000));  // millis in a day   }   // Ideally we'd use methods like these, but Tea only allows property   // access on an object.  These won't be visible.   public boolean isNewWithin(int days) {     return getCreatedAgeInDays() < days;   }   public boolean isUpdatedWithin(int days) {     return getModifiedAgeInDays() < days;   }   public static Tool[] loadTools(String toolsFile) throws Exception {     // Read the tool data from an XML file containing <tool> elements     // Use the JDOM API to keep things simple (http://jdom.org)     List toolObjects = new LinkedList();     SAXBuilder builder = new SAXBuilder();     Document document = builder.build(new File(toolsFile));     Element root = document.getRootElement();     List toolElements = root.getChildren("tool");     Iterator i = toolElements.iterator();     while (i.hasNext()) {       Element tool = (Element) i.next();       Tool t = new Tool();       t.id = tool.getAttribute("id").getIntValue();       t.name = tool.getChild("name").getTextTrim();       t.homeURL = tool.getChild("homeURL").getTextTrim();       t.comments = tool.getChild("comments").getTextTrim();       t.stateFlag = tool.getChild("stateFlag").getTextTrim();       t.createdTime = Timestamp.valueOf(                         tool.getChild("createdTime").getTextTrim());       t.modifiedTime = Timestamp.valueOf(                          tool.getChild("modifiedTime").getTextTrim());       toolObjects.add(t);     }     return (Tool[]) toolObjects.toArray(new Tool[0]);   } }

Notice that although the class has public variables holding its state, they aren't visible from Tea templates. Tea templates have access only to the functions declared by the installed contexts and to the bean properties of the objects returned by those functions. That's why the Tool class has various accessor methods. Tool also has two convenience methods to return the number of days since the record was created and modified. One might be tempted to use an isNewWithin(int days) or isUpdatedWithin(int days) method. However, the template cannot see the method because this does not appear as a bean property.

Example 14-12 shows a simple template frontend for this application. It's named toolview1 and accepts an optional state parameter so views can be limited to tools of a particular state. A screen shot of its output is given in Figure 14-3.

Example 14-12. A Simple View of the Tools
<% template toolview1(String state) %> <%   if (state == null) {     tools = getTools("live");   }   else {     tools = getTools(state)   } %> <% foreach (tool in tools) { %>   <HR SIZE=2 ALIGN=LEFT>   <H3>   <% tool.name %>   <%   if (tool.createdAgeInDays < 45) {     '<FONT COLOR=#FF0000><B> (New!) </B></FONT>'   }   else if (tool.modifiedAgeInDays < 45) {     '<FONT COLOR=#FF0000><B> (Updated!) </B></FONT>'   }   %>   </H3>   <A HREF="<% tool.homeURL %>"><% tool.homeURL %></A><BR>   <% tool.comments %> <% } %>
Figure 14-3. A tools listing with no surrounding content

As you can see, the output lacks the decoration (header, sidebar, footer) needed for a professional page. We can add such decoration by calling on other templates, as shown in the revised toolview2 in Example 14-13.

Example 14-13. A More Complete View of the Tools
<% template toolview2(String state) %> <%     title = "Tool Listing"     deck = "A list of content creation tools"     desc = "Without tools, people are nothing more than animals.  And " &            "pretty weak ones at that.  Here's a list of servlet-based " &            "content creation tools you can use so you won't be a servlet " &            "weakling." %> <% call header(title, deck, desc) %> <%   if (state == null) {     tools = getTools("live");  // semicolon is permitted but not required   }   else {     tools = getTools(state)   } %> <% foreach (tool in tools) { %>   <HR SIZE=2 ALIGN=LEFT>   <H3>   <% tool.name %>   <%   if (tool.createdAgeInDays < 45) {     '<FONT COLOR=#FF0000><B> (New!) </B></FONT>'   }   else if (tool.modifiedAgeInDays < 45) {     '<FONT COLOR=#FF0000><B> (Updated!) </B></FONT>'   }   %>   </H3>   <A HREF="<% tool.homeURL %>"><% tool.homeURL %></A><BR>   <% tool.comments %> <% } %> <% call footer() %>

This new template defines variables for the page title, deck, and description. Then it calls a header template passing along these values. The header template generates the header and sidebar content, then lets the toolview2 template add the core content. At the end of the page, the footer template adds the page footer. Sample header and footer templates are shown in Example 14-14 and Example 14-15. The improved output can be seen in Figure 14-4.

Example 14-14. The Header File
<% template header(String title, String deck, String desc) %> <HTML><HEAD><TITLE><% title %></TITLE></HEAD> <BODY BGCOLOR="#FFFFFF" BACKGROUND="/images/background.gif"       LINK="#003333" ALINK="#669999" VLINK="#333333"> <IMG src="/books/1/318/1/html/2//images/banner.gif" WIDTH=600 HEIGHT=87 BORDER=0><BR> <TABLE> <TR> <TD WIDTH=125 VALIGN=TOP>  <BR><BR><BR>  <FONT FACE="Arial,Helvetica" SIZE="+1" COLOR="#FF0000">  <A HREF="/index.html">Home</A><BR>  <A HREF="/hosting.html">Hosting</A><BR>  <A HREF="/engines.html">Engines</A><BR>  </FONT> </TD> <TD WIDTH=475>   <TABLE CELLPADDING=5><TR><TD WIDTH=600 BGCOLOR="#006699" VALIGN=TOP>   <B><FONT FACE="Arial,Helvetica" SIZE="+2">   <% title %>   </FONT></B>   </TD></TR></TABLE>   <B><FONT FACE="Arial,Helvetica" SIZE="+1" COLOR="#003366">   <% deck %>   </FONT></B><P>   <P>   <FONT FACE="Arial,Helvetica">   <% desc %>
Example 14-15. The Footer File
<% template footer() %>  </FONT> </TD> </TR> <TR> <TD></TD> <TD WIDTH=475 ALIGN=CENTER COLSPAN=3> <HR> <FONT FACE="Arial,Helvetica"> <A HREF="/index.html">Home</A>&nbsp;&nbsp; <A HREF="/hosting.html">Hosting</A>&nbsp;&nbsp; <A HREF="/engines.html">Engines</A>&nbsp;&nbsp;<P> </FONT> <TABLE WIDTH=100%> <TR> <TD WIDTH=260 ALIGN=LEFT VALIGN=TOP> <FONT FACE="Arial,Helvetica"> <A HREF="/copyright.html">Copyright</A> &copy; 2000 Jason Hunter<BR> All Rights Reserved.</TD> <TD WIDTH=5></FONT></TD> <TD WIDTH=230 ALIGN=RIGHT VALIGN=TOP> <FONT FACE="Arial,Helvetica"> Contact: <A HREF="mailto:webmaster@servlets.com">webmaster@servlets.com</A> </FONT></TD> </TR> </TABLE> </TD> </TR> </TABLE> </BODY> </HTML>
Figure 14-4. A tools listing with surrounding content

Following this design, changes to the header, sidebar, or footer are isolated to single files. It also is possible to use a single file to lay out the entire page, inserting core content using the <% ... %> command. This approach provides more power and allows the core section of the page to not know about its outside formatting, although it takes a little getting used to. Be sure to read the TeaServlet documentation for more information.


Last updated on 3/20/2003
Java Servlet Programming, 2nd Edition, © 2001 O'Reilly

< BACKCONTINUE >


Java servlet programming
Java Servlet Programming (Java Series)
ISBN: 0596000405
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net