|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 5
Discuss how Swing implements the composite pattern with the Component and Container classes.
Your last assignment asked you to download Struts from http://jakarta.apache.org/struts/index.html and implement your own Struts action class.
For this assignment, I decided to implement a Struts action in conjunction with the JSP Standard Tag Library (JSTL) to internationalize Example 1's Web application. Although Struts provides the necessary infrastructure to internationalize your Web applications, you should use JSTL for that task, because JSTL is a standard. At some point, the Struts internationalization capabilities will probably be deprecated or integrated with JSTL.
After I internationalized Example 1's Web application with a Struts action and JSTL, I localized that application for Chinese. Figure H1 illustrates the result.
Note: I don't know a single word of Chinese, let alone how to write the language, so Figure H1's Chinese is fabricated from arbitrary Unicode strings. But it looks cool, regardless.
Figure H1. Internationalization with a Struts Action. Click on thumbnail to view full-size image.
Notice I specified the href attributes in Example 12's flags.jsp as empty strings, so when you click on the flags, the servlet container reloads the current JSP. Therefore, the first step
towards internationalizing the Web application is to specify a URL for those attributes, as listed in Example H1:
<table>
<tr><td>
<a href='flags.do?locale=en-GB&fwdPage=<%=request.getServletPath()%>'>
<img src='graphics/flags/britain_flag.gif'/></a>
<a href='flags.do?locale=de-DE&fwdPage=<%=request.getServletPath()%>'>
<img src='graphics/flags/german_flag.gif'/></a>
<a href='flags.do?locale=zh-ZH&fwdPage=<%=request.getServletPath()%>'>
<img src='graphics/flags/chinese_flag.gif'/></a>
</td></tr>
</table>
The URL for each href attribute is the same: flags.do. Two request parameters are tacked onto that URL: one for the locale corresponding to the flag and another that represents
the current JSP's path. You obtain the latter request parameter by invoking the Http.ServletRequest.getServletPath() method.
In the application's deployment descriptor, I mapped all URLs ending in .do to the Struts action servlet, like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<!-- Action Servlet Configuration -->
<servlet>
<servlet-name>
action
</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
...
<load-on-startup/>
</servlet>
<!-- Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
...
</web-app>
Note: See my "Take Command of Your Software" (JavaWorld, June 2002) article for more information about Struts and the Struts action servlet.
Next, I mapped the path /flags to the Struts action actions.FlagAction in the Struts configuration file, listed in Example H3:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<action-mappings>
<action path='/flags' type='actions.FlagAction'/>
</action-mappings>
<plug-in className="org.apache.struts.tiles.TilesPlugin" >
<set-property property="definitions-config"
value="/WEB-INF/tiles-defs.xml" />
<set-property property="definitions-debug" value="2" />
<set-property property="definitions-parser-details"
value="2" />
<set-property property="definitions-parser-validate"
value="true" />
</plug-in>
</struts-config>
Because of that mapping, the URL flags.do causes the Struts action servlet to invoke the actions.FlagAction.execute() method; therefore, clicking on a flag will invoke the actions.FlagAction.execute() method. Example H4 lists the actions.FlagAction class:
package actions;
import javax.servlet.ServletContext;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import javax.servlet.jsp.jstl.core.Config;
public class FlagAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
String locale = request.getParameter("locale");
Config.set(getServlet().getServletContext(),
Config.FMT_LOCALE, locale);
return new ActionForward(request.getParameter("fwdPage"));
}
}
The actions.FlagAction.execute() method obtains a reference to the locale request parameter and passes that value to the JSTL Config class's set() method. That method stores the string representing the locale in the FMT_LOCALE configuration setting, which JSTL uses to localize text and format numbers, currencies, percents, and dates.
Now that I've specified a locale for JSTL internationalization actions, I next specify a resource bundle in the application's deployment descriptor, an excerpt of which is listed in Example H5:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<!-- Define the basename for a resource bundle for I18N -->
<context-param>
<param-name>
javax.servlet.jsp.jstl.fmt.localizationContext
</param-name>
<param-value>
resources
</param-value>
</context-param>
...
</web-app>
The resource bundle basename resources is specified for the javax.servlet.jsp.jstl.fmt.localizationContext context-initialization parameter. That means JSTL will search for a file named resources_en.properties when the locale is set to British English (en-GB) and resources_zh.properties when the locale is set to Chinese (zh-ZH).
Now that I've specified a resource bundle and a locale for the JSTL internationalization actions, I next modify the JSP files to use those actions, as Examples H6-H9 demonstrate:
<%@ page contentType='text/html; charset=UTF-8' %> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt' %> <p> <font size='5'><fmt:message key='sidebar.heading'/></font><p> <a href='index.jsp'><fmt:message key='sidebar.link.1.name'/></a><br> <a href='products.jsp'><fmt:message key='sidebar.link.2.name'/></a><br> <a href='downloads.jsp'><fmt:message key='sidebar.link.3.name'/></a><br> <a href='sales.jsp'><fmt:message key='sidebar.link.4.name'/></a><br> <a href='contact.jsp'><fmt:message key='sidebar.link.5.name'/></a><br>
<%@ page contentType='text/html; charset=UTF-8' %> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt' %> <font size='6'><fmt:message key='header.heading'/></font> <hr>
<%@ page contentType='text/html; charset=UTF-8' %> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt' %> <font size='4'><fmt:message key='content.heading'/></font>
<%@ page contentType='text/html; charset=UTF-8' %> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt' %> <hr> <fmt:message key='footer.message'/>
Examples H6-H9's JSPs use the JSTL <fmt:message> action to extract Unicode strings from the resource bundle specified in the deployment descriptor. Examples H10 and H11 list
the resource bundles for English and Chinese, respectively:
header.heading=Welcome to Sabreware, Inc. content.heading=Page-specific content goes here footer.message=Thanks for stopping by! sidebar.heading=Links sidebar.link.1.name=Home sidebar.link.2.name=Products sidebar.link.3.name=Downloads sidebar.link.4.name=Sales sidebar.link.5.name=Contact Us
header.heading=\u5bc6\u7801\u63d0\u793a\u95ee\u9898 Sabreware, Inc. content.heading=\u6709\u6548\u671f\u9650 footer.message=\u4eca\u5929\u662f sidebar.heading=\u8fd9\u91cc sidebar.link.1.name=\u767b\u5f55 sidebar.link.2.name=\u540d sidebar.link.3.name=\u59d3 sidebar.link.4.name=\u7701\u4efd sidebar.link.5.name=\u7501\u4cfe
In an email to me, Joseph Friedman wrote:
In "Decorate Your Java Code" (JavaWorld, December 2001), you write:
"The enclosing object—known as a decorator—conforms to the interface of the object it encloses, allowing the decorator to be used as though it were an instance of the object it encloses."
However, the code example decorates the
FileReaderwith aLineNumberReaderand callsreadLine(), which is not in theFileReaderinterface; thus you are not using theLineNumberReadertransparently.
Both FileReader and LineNumberReader conform to the interface defined by the Reader class, which they both extend. The idea is that you can pass the decorator to any method that expects a reference to a Reader. Those methods remain blissfully ignorant of that decorator's special capabilities—in this case, the ability to read files
and produce line numbers. However, if you know about those special capabilities, you can take advantage of them.
The fact that the decorator possesses (one or more) methods that the decorated object lacks does not in any way violate the Decorator pattern's intent; in fact, that's the central feature of that pattern: to add functionality at runtime to an object by decorating objects recursively.
If you look at Design Patterns page 173, you will see this:
Read more about Core Java in JavaWorld's Core Java section.
Decorator subclasses are free to add operations for specific functionality. For example,ScrollDecorator'sScrollTooperation lets other objects scroll the interface *if* they know there happens to be aScrollDecoratorobject in the interface.