Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
XML and JSP Alex Chaffee, [email protected] http://www.purpletech.com ©1996-2000 jGuru.com Core Technologies • JSP - Server-side Java • XML - Data storage and exchange format Web Sites' Needs • vast amount of data • uniform presentation • mostly reading, limited writing Solution • data stored in XML files • UI presented in JSP Why not a database? • • • • separate process or machine higher maintenance SQL sucks Object-relational mapping Why XML? • Text files are very easy to deal with – Edit, backup, copy, download, upload with standard tools • Hierarchical data model Why not XML? • High volume of writes • Complicated or variable queries • Failure tolerance XML-Database Gaps • Not indexed or searchable (yet :-) • No transactions (but can do simple file locking) Application: Online Photo Album • Picture fields - title, date, caption - image - thumbnails • Image fields - source file - height, width Sample Data File <picture> <title>Alex On The Beach</title> <date>1999-08-08</date> <caption>Trying in vain to get a tan</caption> <image> <src>alex-beach.jpg</src> <width>340</width> <height>200</height> </image> Sample Data File (cont.) <thumbnails> <image> <src>alex-beach-sm.jpg</src> <width>72</width> <height>72</height> </image> <image> <src>alex-beach-med.jpg</src> <width>150</width> <height>99</height> </image> </thumbnails> </picture> Sample Filesystem summer99/alex-beach.pix summer99/alex-beach.jpg summer99/alex-beach-sm.jpg summer99/alex-beach-med.jpg summer99/alex-snorkeling.pix etc. Techniques • Many ways to bring XML into JSP • DOM – You can use classes implementing the DOM interface to parse and inspect the XML file • JDOM – Better than DOM • XPath – You can use an XPath processor (like Resin) to locate elements in the XML file by path name – /picture[1]/thumbnails[2]/width Techniques (cont.) • XSL – You can use an XSL processor to transform the XML into HTML • Cocoon – You can use the open-source Cocoon framework • Roll your own Bean – You can write a wrapper class that uses one of the other techniques to load the data into a custom JavaBean Note that these techniques could be applied equally well to an XML stream you receive from another source, like a client or an application server. JSP Engine • Tomcat – It supports the most up-to-date versions of the JSP and Servlet specs – It's endorsed by Sun and Apache – You can run it "standalone" without configuring a separate Web server – It's open source JSP Include Structure • I use an "init.jsp" file • Store common functions, imports, constants, variables, <jsp:useBean> initializers • Include using <%@include file="init.jsp"%> – Acts like C #include • For other purposes, use <jsp:include page="…"/> – Compiles included page separately Finding the file • How do you know which file to load? – CGI – request.getParameter("file") • How do you know which directory the file is in? – Ask the servlet context – String picturefile = application.getRealPath("/" + request.getParameter("file")); – String picturefile = getServletContext().getRealPath("/" + request.getParameter("file")); • Important: validate the path – what if the value "file=../../../../etc/passwd" were entered? The Document Object Model • DOM: W3C interfaces for accessing inside of an XML document • API is fairly cumbersome • My DOMUtils contains simple wrappers for DOM calls Accessing the node values with DOMUtils Document doc = DOMUtils.xml4jParse(picturefile); Element nodeRoot = doc.getDocumentElement(); Node nodeTitle = DOMUtils.getChild(nodeRoot, "title"); String title = (nodeTitle == null) ? null : DOMUtils.getTextValue(nodeTitle); Node nodeImage = DOMUtils.getChild(nodeRoot, "image"); Node nodeSrc = DOMUtils.getChild(nodeImage, "src"); String src = DOMUtils.getTextValue(nodeSrc); Embedding XML values in JSP/HTML <table bgcolor="#FFFFFF" border="0" cellspacing="0" cellpadding="5"> <tr> <td align="center" valign="center"> <img src="<%=src%>" width="<%=width%>" height="<%=height%>" border="0" alt="<%=src%>"></td> </tr> </table> Full Source Code See picture-dom.jsp JSP Beans • Problem with above: commingles presentation and data – Embeds Java code directly in JSP scriptlet • Cleaner approach: use JSP Beans – Scriptlets good for control flow, minor variable access, prototyping – JavaBeans for significant Java code • database access, business logic, other algorithms • Prototype with scriptlets, polish with Beans – More modular – Can reuse code • But wait until you have code worth reusing Picture Beans • Picture.java, Image.java, etc. • constructors or setter methods that take in a DOM node or a file name from which to extract their values • get/set methods for each sub-element Picture.java (interface) public interface Picture { public void setTitle(String title); public String getTitle(); public void setDate(String date); public String getDate(); public void setCaption(String caption); public String getCaption(); public void setImage(Image image); public Image getImage(); public void setThumbnails(Thumbnails thumbnails); public Thumbnails getThumbnails(); } DOMPicture.java (implementation) public class DOMPicture implements Picture { private String title; private String date; private String caption; private Image image; private Thumbnails thumbnails; public DOMPicture() {} public DOMPicture(Node node) { setNode(node); } DOMPicture (cont.) public void setNode(Node node) { Node nodeTitle = DOMUtils.getChild(node, "title"); setTitle((nodeTitle == null) ? null : DOMUtils.getTextValue(nodeTitle)); Node nodeCaption = DOMUtils.getChild(node, "caption"); setCaption((nodeCaption == null) ? null : DOMUtils.getTextValue(nodeCaption)); Node nodeDate = DOMUtils.getChild(node, "date"); setDate((nodeDate == null) ? null : DOMUtils.getTextValue(nodeDate)); Node nodeImage = DOMUtils.getChild(node, "image"); setImage(new DOMImage(nodeImage)); Node nodeThumbnails = DOMUtils.getChild(node, "thumbnails"); setThumbnails(new DOMThumbnails(nodeThumbnails)); } DOMPicture (cont.) public void setTitle(String title) { this.title = title; } public String getTitle() { return title; } public void setDate(String date) { this.date = date; } public String getDate() { return date; } etc… Source Code Notes • • • • I defined interfaces separately from implementation classes, so you are free to choose alternate implementations in the future. You may want to store the values in a List, or in the DOM itself, or even a database. The beans are defined in a custom package, picturebeans. All JSP beans must be in a package (most JSP engines won't be able to find classes that are in the default package). I provided set methods in addition to get methods. At the moment, you're only reading; however, in the future, you may want to let users edit pictures, so you're planning for the ability to change and write properties. I now have to say "<%=picture.getCaption()%>" instead of just "<%=caption%>", since the values are stored in a bean rather than in local variables. However, if you want, you can define local variables like "String caption = picture.getCaption();". This is acceptable since it makes the code a little easier to read and understand. Bang, Zoom, to the Moon • • • define a parameter, zoom, whose value determines which of the thumbnail images to display clicking on a "Zoom In" or "Zoom Out" button will select the next or previous thumbnail in the list finding the right thumbnail – • (Image)picture.getThumbnails().get(i) "Zoom In" and "Zoom Out" links – generate a recursive reference to the same page, with different parameters. – request.getRequestURI() <% if (zoom < (thumbnails.size() -1)) { out.print("<a href='" + request.getRequestURI() + "?file=" + request.getParameter("file") + "&zoom=" + (zoom+1) + "'>"); out.print("Zoom In</a>"); } %> JSP Bean Tags • <jsp:useBean> can replace embedded Java code • Why bother? – The tag syntax is arguably less intimidating to HTML designers. – useBean has a scope parameter that automatically figures out whether the bean should be stored as a local variable, a session variable, or an application attribute. – If the variable is persistent (session or application), useBean initializes it if necessary, but fetches the variable if it already exists. – It's potentially more portable to future versions of the JSP spec, or alternate implementations (for example, a hypothetical JSP engine that stores variables in a database, or shares them across server processes). Picture App with <jsp:useBean> <jsp:useBean id="picture" scope="request" class="picturebeans.DOMPicture"> <% Document doc = DOMUtils.xml4jParse(picturefile); Element nodeRoot = doc.getDocumentElement(); nodeRoot.normalize(); picture.setNode(nodeRoot); %> </jsp:useBean> • or, if you define a setFile(String) method inside DOMBean: <jsp:useBean id="picture" scope="request" class="picturebeans.DOMPicture"> <jsp:setProperty name="picture" property="file" value="<%=picturefile%>"/> </jsp:useBean> Caching • XML Parsing takes time • You must cache the results of a DOM traversal for later requests for the same file • My CachedFS.java keeps a cache – Also checks if the file has changed, reloads if necessary – So does JDOM Bean • Define it as an application-scope bean – In init.jsp, so you centralize the initialization code Using FSCache <jsp:useBean id="cache" class="com.purpletech.io.CachedFS" scope="application"> <% cache.setRoot(application.getRealPath("/")); cache.setLoader( new CachedFS.Loader() { // load in a single Picture file public Object process(String path, InputStream in) throws IOException { try { Document doc = DOMUtils.xml4jParse (new BufferedReader(new InputStreamReader(in))); Element nodeRoot = doc.getDocumentElement(); nodeRoot.normalize(); Picture picture = new DOMPicture(nodeRoot); return picture; } catch (XMLException e) { e.printStackTrace(); throw new IOException(e.getMessage()); } } }); %> </jsp:useBean> XPath • a simple syntax for locating nodes in an XML tree • easier to use than DOM • embed the entire path in a string -- for example, "/picture/thumbnails/image[2]". • Resin by Caucho ncludes an XPath processor – can use the Caucho XPath object on its own, without buying into the rest of the Resin framework. – Node verse = XPath.find("chapter/verse", node); • Can put it in Picture Beans, and/or in JSP XSL • Different style of solution to same problem • Possible to combine with this technique • Different philosophy: – JSP treats HTML as primary – XSL treats template rules (fragments) as primary XML Data Binding • Lots of other approaches • Adelard: JSR 031 • See my XML and Java talk Conclusion