The catalog viewer project is available on the CD that accompanies this book. Copy the project directory from the CD to your hard disk and then go to the command line and change to the root of the project. You can run the catalog viewer with the catalog command (see Figure 1.10). Figure 1.10. Running the catalog viewer.
Caution You need a version of Java 2 (JDK 1.2 or above) installed on your machine to run this project. The project should run on JDK 1.1, but you will need to adapt the catalog.bat file. You also need a SAX 2.0 “compliant XML parser to run this project. The project on the accompanying CD uses Xerces, which is available on the CD and from http://xml.apache.org. If you switch to another parser, you will need to update PARSER_NAME in CatalogViewer . Pattern BenefitsThe major benefits of the builder and visitor patterns are as follows :
Replacing the DirectorThe benefit of adopting a flexible design is that it is simple to change the application. For example, you can
Listing 1.15 demonstrates the last advantage. As the name implies, the DOMDirector is a director built on a DOM parser. This director makes exactly the same calls to the builder, so changes are really limited to one class! Although a DOM parser is less efficient, because it uses more memory, it might be the only parser available to you. Listing 1.15 DOMDirector.javapackage com.psol.catalog; import org.w3c.dom.*; public class DOMDirector { protected CatalogBuilder builder; public DOMDirector(CatalogBuilder builder) { this.builder = builder; } public void walkDocument(Document document) { Element el = document.getDocumentElement(); if(el.getTagName().equals("Catalog")) walkCatalog(el); } public void walkCatalog(Element element) { NodeList children = element.getChildNodes(); for(int i = 0;i < children.getLength();i++) { Node node = children.item(i); if(node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element)node; if(el.getTagName().equals("Product")) walkProduct(el); } } builder.buildCatalog(); } public void walkProduct(Element element) { NodeList children = element.getChildNodes(); String text = null, image = null; for(int i = 0;i < children.getLength();i++) { Node node = children.item(i); if(node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element)node; if(el.getTagName().equals("Text")) text = extractContent(el); else if(el.getTagName().equals("Image")) image = extractContent(el); else if(el.getTagName().equals("Descriptions")) walkDescriptions(el); } } String id = element.getAttribute("id"), st = element.getAttribute("checked"); boolean checked = Boolean.valueOf(st).booleanValue(); if(null == image) builder.buildTextualProduct(text,id,checked); else builder.buildVisualProduct(text,id,checked,image); } public void walkDescriptions(Element element) { NodeList children = element.getChildNodes(); for(int i = 0;i < children.getLength();i++) { Node node = children.item(i); if(node.getNodeType() == Node.ELEMENT_NODE) { Element el = (Element)node; if(el.getTagName().equals("Text")) { String text = extractContent(el), lang = el.getAttribute("xml:lang"); builder.buildDescription(lang,text); } } } } public String extractContent(Element element) { // currently ignores entities, CDATA section, etc. element.normalize(); Node child = element.getFirstChild(); if(child != null && child.getNodeType() == Node.TEXT_NODE) { Text text = (Text)child; return text.getData(); } else return null; } } Replacing the VisitorThe catalog viewer saves the complete catalog so the customer must email a file that is larger than required. However, it would be more efficient to save a smaller file with the list of products the customer selected. This is easy to accomplish by writing a new visitor class, such as the XMLRequestVisitor shown in Listing 1.16. Listing 1.16 XMLRequestVisitor.javapackage com.psol.catalog; import java.io.*; public class XMLRequestVisitor implements CatalogVisitor { protected PrintWriter pw; public XMLRequestVisitor(PrintWriter pw) { this.pw = pw; } public void visitCatalog(Catalog catalog) throws IOException { pw.println("<?xml version='1.0'?>"); pw.println("<Request>"); for(int i = 0;i < catalog.getSize();i++) catalog.productAt(i).accept(this); pw.print("</Request>"); pw.flush(); } public void visitVisualProduct(VisualProduct product) throws IOException { visitProduct(product); } public void visitTextualProduct(TextualProduct product) throws IOException { visitProduct(product); } public void visitProduct(Product product) throws IOException { if(product.isChecked()) { pw.print("<Product id='"); // works with any Writer encoding but EBCDIC String value = product.getId(); for(int i = 0;i < value.length();i++) { char c = value.charAt(i); if(c == '\ '') pw.print("'"); else if(c == '&') pw.print("&"); else if(c > '\ u007f') { pw.print("&#"); pw.print(Integer.toString(c)); pw.print(';'); } else pw.print(c); } pw.println("\ '/>"); } } public void visitDescription(Description description) throws IOException { } } |