Java Servlet Programming, 2nd Edition > 14. The Tea Framework > 14.5 Tea Applications |
14.5 Tea ApplicationsSo far we've been looking at Tea templates alone, and they are very weak intentionally weak. But Tea templates are like frontline infantry soldiers when alone they are weak but when teamed with advanced backend air support, they become extremely powerful. Here are some ways to make Tea templates more powerful. Templates may access any function from any "application" installed into the TeaServlet via the TeaServlet.properties file. (Each web application can have a different TeaServlet.properties file and thus a different set of installed applications.) Templates call functions by specifying within a Tea code block the function name followed by open and close parentheses. Functions may accept parameters and may return values: <% list = getRecords() %> <% removeRecord(8086) %> The TeaServlet administration screen shows a list of all available functions from all installed applications. Should two applications declare the same function, a template can prefix the function call with the application name to remove the ambiguity: <% list = RecordListApp.getRecords() %> There's a set of utility functions available across all templates intended to help with basic text-processing chores. The following sections list some of the most frequently called utility functions. 14.5.1 Text ProcessingHere are some common text-processing functions.
14.5.2 Content HandlingHere are some common content-handling methods.
14.5.3 Request/Response HandlingIn addition, here are some frequently-used request/response methods.
The template in Example 14-5 demonstrates how a template may call on the utility functions to print an ad-click-through percentage for a given day. The date and percentage are formatted in the French style. Example 14-5. French Clicks<% template clicks() %> <HTML><HEAD><TITLE>Testing the Tea Built-In Functions</TITLE></HEAD><BODY> <% // Set the locale; it remains for all later template output setLocale("fr", "CA") // Quebec // Specify how time and numbers should be formatted dateFormat("d MMMM yyyy") numberFormat("#0.00%") // Some fake data clicks = 485.0 accesses = 7673.0 %> <H2><% currentDate() %></H2> Le pourcentage: <% clicks/accesses %> </BODY></HTML> The template writes something like this, with the date and percentage appropriate for someone living in Quebec: 16 juillet 2000 Le pourcentage: 6,32% 14.5.4 Writing a Tea ApplicationNow let's look at how to write a custom Tea application. It's easy: just write an application class and a context class. All application classes implement the com.go.teaservlet.Application interface. Just like a servlet, the Application interface has init( ) and destroy( ) methods to handle lifecycle issues. Instead of a service( ) method the Application has a createContext( ) and getContextType( ) pair of methods. The createContext( ) method returns a context object whose methods are made available to templates as functions. The getContextType( ) method returns the java.lang.Class of the object returned by createContext( ) to facilitate type checking. The following two examples show a simple application that attempts to determine the name of the user through various means. The NameApp class is the application class (Example 14-6); the NameContext class is the context object created by NameApp and made available to templates (Example 14-7). Example 14-6. The NameApp Classimport com.go.teaservlet.*; import javax.servlet.*; public class NameApp implements Application { // Both init(ApplicationConfig) and destroy() must be implemented because // they are declared in the Application interface. They can be left empty. public void init(ApplicationConfig config) throws ServletException { } // Creating a context provides functions accesible from the templates. public Object createContext(ApplicationRequest request, ApplicationResponse response) { // You often pass on the request and response even if // they are not used, since they may be used later return new NameContext(request, response); } // This method must be implemented to return the class of the object // returned by createContext() public Class getContextType() { return NameContext.class; } public void destroy() { } } The TeaServlet calls the init( ) method a single time when the application is first loaded to give the application an opportunity to perform initialization. It calls destroy( ) a single time on shutdown to give the application a chance to clean up. The init( ) method accepts an ApplicationConfig parameter, which is a subinterface of ServletConfig with three additional methods getLog( ) , getName( ), and getProperties( ) to retrieve the application log, name, and initialization properties. The TeaServlet calls the createContext( ) method before request handling and makes available all the methods of the returned context object as functions for the requested Tea template. If there needs to be a different context per user, that can be easily managed using standard session-tracking code in the createContext( ) method. The createContext( ) method accepts ApplicationRequest and ApplicationResponse as parameters. These are subinterfaces of HttpServletRequest and HttpServletResponse with the addition of a few Tea methods. Example 14-7. The NameContext Classimport com.go.teaservlet.*; import javax.servlet.*; import javax.servlet.http.*; public class NameContext { ApplicationRequest request; ApplicationResponse response; String name; public NameContext(ApplicationRequest request, ApplicationResponse response) { this.request = request; this.response = response; } public String getName() { // If we already determined the user's name, return it if (name != null) { return name; } // Try to determine the name of the user name = request.getRemoteUser(); // If the login name isn't available, try reading a parameter if (name == null) { name = request.getParameter("name"); } // If the name isn't available as a parameter, try the session if (name == null) { name = (String) request.getSession().getAttribute("name"); } // If the name isn't in the session, try a cookie if (name == null) { Cookie[] cookies = request.getCookies(); for (int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equals("name")) { name = cookies[i].getValue(); } } } // If the name isn't in a cookie either, give up return name; } } The getName( ) method attempts to determine the name of the client user by searching the client's login credentials, parameter list, session data, and request cookies. It returns null if no name information could be found. Templates access the name by calling the getName( ) function. Notice the context calculates the client's name in getName( )and not in the constructor. This is a performance trick. If the logic were in the constructor it would be executed during the handling of each request, whether or not any template actually called getName( ). To make the NameApp application available requires the following short addition to the TeaServlet.properties file: "NameApp" { class = NameApp } You can verify the application was properly loaded by browsing the Applications link of the TeaServlet administration application.[2]
With this application loaded, any template can display the client's name using the getName( ) function: <% template names() %> <% setContentType("text/plain") nullFormat("Unknown") %> Your name is <% getName() %>.
|