Download Java in XML - Purple Tech

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
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