Java in XML - Purple Tech

Download Report

Transcript Java in XML - Purple Tech

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