How XML Enhances JDBC and vice versa When you combine XML with J2EE Java 2, Enterprise Edition technologies and standard Internetprotocols such as HTTP, you can write enterprise applicat
Trang 1XPath oddities like this compel us to recommend against the use of long paths like A/B in predicates.Most likely, the meaning you wanted is actually a nested predicate like
/Order[Product[@UnitPrice > 10]] anyway
Because SQL XML does not support positional predicates, it uses "any" semantics for both of theseXPaths That is, both /Order[0 + Product/@UnitPrice > 10] and
/Order[Product/@UnitPrice > 10] produce the same XML result in SQL XML
This deviation from the W3C standard also applies to relational and equality operators These operatorsapply special conversion rules to their operands that we will not explain in detail here For example, anexpression @Date > '1998-10-01' should first convert both the nodeset @Date and the string'1998-10-01' to number (which will result in NaN), and then compare them (which will result infalse, since NaN compared with anything is false) SQL XML instead performs a string comparison,with the expected result (true if and only if the value of @Date is a date later than the one indicated inthe string)
Here's an XPath that attempts string and date comparisons These would not work in ordinary XMLdocuments, but do work in SQL XML:
/Customer[@CustomerID > 'PARIS']/Order[@OrderDate <= '1999-01-01']
which results in the XML
<Order OrderID="10322" OrderDate="1996-10-04">
<Product ProductID="P52" UnitPrice="7.0000" Units="38"/>
</Order>
<Order OrderID="10354" OrderDate="1996-11-14">
<Product ProductID="P1" UnitPrice="18.0000" Units="39"/>
<Product ProductID="P29" UnitPrice="123.7900" Units="0"/>
</Order>
<Order OrderID="10474" OrderDate="1997-03-13">
<Product ProductID="P14" UnitPrice="23.2500" Units="35"/>
<Product ProductID="P28" UnitPrice="45.6000" Units="26"/>
<Product ProductID="P40" UnitPrice="18.4000" Units="123"/>
<Product ProductID="P75" UnitPrice="7.7500" Units="125"/>
</Order>
<! >
At the time of this writing, none of the XPath string functions (concat(), substring(), etc.) aresupported Microsoft has announced intentions to support these functions in the near future
XPath and the XML View
XPath works by translating the XPath into an equivalent FOR XML EXPLICIT query During thistranslation process, XPath makes use of the many annotations provided in the XML View
XPath applies join relationships when navigating from one node to another If the nodes are joined inthe schema, then the join relationship will be used in the SQL query Predicates correspond to existencetests (WHERE EXISTS)
Trang 2Nodes that have an id-prefix are converted to string, and then the prefix is prepended to the value Notethat this prevents using those values as numbers in the XPath For example,
/Product[@ProductID=11] is an error; the correct XPath uses the id prefix:
/Product[@ProductID='P11']
In many cases, key information is required to correctly order and nest the resulting XML If an XPathquery seems to be returning odd results, or returns a FOR XML EXPLICIT error, the problem may bethat the schema is missing sql:key-fields Read the section about this annotation for instructions onits use
Finally, XPath queries must perform many data conversions XPath translates first from the SQL type tothe XDR type, and then from the XDR type to the XPath type This means that specifying XDR andSQL types in the schema can help eliminate unnecessary conversions When the query converts acolumn used as an index (for example, /Customer[@CustomerID='ALFKI']), eliminating theunnecessary conversion can result in a ten-fold performance improvement of the XPath query
Default Schema
XPath works best with an XML View, but can work without any schema at all – with some restrictions.These restrictions (names, flat hierarchy) are the same restrictions as on the default mapping used by an
XML View (See the earlier section, "The Default Mapping," for details.)
In addition, an XPath with no XML View must select the value of a single column from a single row.Because there is no schema to describe how the XML should be shaped, the XPath cannot return XML.The default schema can be especially convenient for so called "direct object" queries that use an XPath-like syntax to access objects in the database For example, the XPath
/Customers[@CustomerID='ALFKI']/@ContactName
is exactly the same as the SQL query
SELECT ContactName FROM Customers WHERE CustomerID='ALFKI'
XPath Parameters
XPath parameters are prefixed with the dollar-sign symbol (for example, $param) SQL XML supportsonly string-valued parameters, but this presents no great difficulties Parameters can be shared amongother queries in a template For example, the following template selects the Customer element with the
id parameter value that was passed to the template (which defaults to "ALFKI"):
Trang 3Additional XPath Axes
XPath is not limited to top-down navigation (from an element to its children and attributes) XPath has arich set of navigation axes, including namespaces, descendants, ancestors, and so on However, at thetime of this writing, SQL XML supports only four axes: child, attribute, parent, and self Inparticular, the popular descendant-or-self shortcut "//" is not supported
All four of these have abbreviated forms that are more commonly used For the child and attributeaxes, we've seen that the abbreviations have the form child or @attribute, respectively For
parent, the short form is two dots ( ) and one dot (.) is the short form for self Thus, the XPath/Customer/Order[ /@CustomerID='ALFKI']
is equivalent to the XPath
The abbreviation is short for parent::node() and the abbreviation is short for self::node()
So the XPath above that uses could also be rewritten as:
/child::Customer/child::Order[parent::node()/attribute::CustomerID='ALFKI']
Updategrams
At this time, there is no W3C standard for updating XML documents Updategrams attempt to fill thisvoid by specifying a standard XML-based language for inserting, updating, and deleting XML data.Updategrams are declarative You describe what the XML currently is and what you want it to become,and the updategram takes care of all the details necessary to make it so Updategrams use the
namespace URI urn:schemas-microsoft-com:xml-updategram, which we will always assign tothe prefix u
In SQL Server 2000, updategram queries are executed through templates Each updategram uses anXML View of the database to determine the SQL query that is required to perform the update
NOTE: Updategrams require the latest SQL XML web release from MSDN, or SQL
Server 2000 SP1 or later The examples in this section are not compatible with the
early beta version of updategrams that was released for SQL Server 2000 beta 2.
Trang 4Every updategram consists of one <u:sync> element, corresponding to one database transaction Thetransaction is described by a sequence of <u:before> and <u:after> pairs Every <before> musthave a matching <after>, and vice-versa; if one is missing, then it is equivalent to one with emptycontent The contents of the <before> element are compared with the contents of its matching
<after> element to determine whether an INSERT, UPDATE, or DELETE is required
To avoid conflicts between multiple, concurrent queries, updategrams employ "optimistic concurrencycontrol" If the current state of the database does not match the XML described in the <before>element, then the transaction will not be committed, and no change will be made Depending on howspecific the <before> element is, the synchronization will effectively range from none at all ("updatealways") to total synchronization ("update only if the row has not changed at all")
To demonstrate updategrams, let's create a table:
CREATE TABLE FictionalCharacters
(cid nvarchar(10) PRIMARY KEY, FirstName nvarchar(40), LastName nvarchar(40))
We now use the following schema, ch15_ex21.xdr, for mapping the table:
<Schema xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes"
xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<ElementType name="First" content="textOnly" />
<ElementType name="Last" content="textOnly" />
<ElementType name="Person" sql:relation="FictionalCharacters"
sql:key-fields="cid">
<AttributeType name="ID" dt:type="id"/>
<attribute type="ID" sql:field="cid"/>
<element type="First" sql:field="FirstName"/>
<element type="Last" sql:field="LastName"/>
Trang 5The result of executing this template, if the updategram succeeds, will be
We can now update this row, using this updategram (ch15_ex22a.xml):
especially NULL
Trang 6Values, Absence and NULL
Up until now, we've said that absence of XML data is equivalent to a SQL NULL value, and vice-versa.Unfortunately, this equivalence presents a problem for an updategram, because optimistic concurrencycontrol applies only to the values in the before element If the value was NULL, it would be absent, andthus would not figure into the equation (even though we might not want to perform the update or delete
if the value has changed away from NULL) Therefore, updategrams need a way to explicitly differentiateNULL values from absent ones
Updategrams allow the user to specify a string value that will be used in the XML in place of a SQLNULL Whenever an XML value is equal to this string, the string is replaced with NULL in the equivalentSQL query The string is specified with the attribute u:nullvalue on the <u:sync> element or
This updategram will commit only if the FirstName is still NULL
Note that when evaluating the value of an element, updategrams don't use the usual definition of stringvalue In XPath syntax, string(element) usually takes all the text node descendants of the elementand concatenates them together in document order, which is equivalent to the XPath
string(element//text()) Updategrams use only the text nodes that are immediate children of theelement, equivalent to the XPath string(element/text()) When the string value of the elementmatches the u:nullvalue, NULL is substituted in its place
Also, updategrams are aware of XDR default That is, when an element or attribute value is absent,updategrams use the default value (if given) in the annotated XDR schema The default is indicated inthe schema on an <AttributeType> or <ElementType> using the default attribute When there is
no default value, no value is used for the absent element or attribute
Trang 7Insert/Update/Delete Heuristics
Now that you understand how an updategram extracts the XML values out of the before and afterelements and how it handles absence and default values, the only remaining piece of the puzzle isdetermining which values in the after element correspond to which values in the before element.Once this matching has been performed, the updategram knows which rows to update, which to delete,and which to insert, and can create the corresponding SQL query to perform that work
An updategram matches elements based on an element key This key can be specified in the annotatedschema using sql:key-fields, or it can be specified in the updategram using the u:id annotation Ifthe u:id method is chosen, then it must be used everywhere in the updategram
As an example, consider the following updategram (ch15_ex24.xml):
<Person u:id="forty-two" ID="HGTTG42"/>
<Person u:id="fifty-four" ID="HGTTG54"/>
</u:before>
<u:after>
<Person u:id="fifty-four" ID="54"/>
<Person u:id="forty-two" ID="42"/>
</u:after>
</u:sync>
Trang 8This updategram needs to change the value of the key itself The only way to do this is to identify theelements using u:id The values used for u:id are arbitrary; they are used only for matching elements
in the updategram, and will not be inserted into the database: as a result, this updategram will not work
Of course, u:id is not limited to key changes; it can be used any time
Parameters
Updategrams use parameters exactly like XPath does, and with a similar syntax Anywhere an
updategram contains the dollar-sign ($) followed by the name of a parameter, the parameter value will
Default Schema
We previously described the subset of XPath that can be executed without a schema Updategrams canalso use a default mapping, with some restrictions These restrictions (names, flat hierarchy) are similar
to the default mapping used by an XML View (See the earlier section, "The Default Mapping," for details).
In addition, updategrams cannot work with any of the SQL types binary, image, ntext, text, orvarbinary in the <before> element and binary, image, or varbinary in the <after> element.Values that map to monetary SQL types (money and smallmoney) must be preceded with a currencysymbol such as $; conversely, values preceded with a currency symbol cannot be inserted, updated, ordeleted from any string type column in the database (char, nvarchar, etc.)
Trang 9Also, the generated value can be returned as part of the template result by using the u:returnidattribute on the u:after element For example, the template
Data Types
All values that map to any of the SQL types binary, image, ntext, text, or varbinary must bemarked in the schema as having that sql:datatype Otherwise, the updategram will not be able togenerate a valid SQL query Similarly, both monetary types (money, smallmoney) must be marked ashaving one of the XDR numeric types to be properly used, even though you could still have an attributetype unitprice, without either datatype
The XDR binary types bin.hex and bin.base64 are used when decoding binary values Binaryvalues cannot be referred to using a dbobject URL (as generated by sql:url-encode)
If an attribute or element has a sql:id-prefix in the schema, then that prefix will be stripped out ofthe value in the updategram
Trang 10Advanced Topics
Namespaces and External Schemas
Most uses of XML require namespaces, whether some externally defined namespace or your owncustom one There are two central concepts required when using namespaces in XML Views:
namespace declarations and the sql:target-namespace annotation
Recall that namespace declarations come in two forms, xmlns="uri" and xmlns:prefix="uri", andare inherited of the descendants of the element where they were declared Namespace URIs are
commonly overloaded for many different purposes – versioning (like the XSL namespaces) and actualURLs (that you can visit on the Web) are just two examples For XML Views, there are three kinds ofnamespace URIs worth mentioning
First, there are the four special namespace URIs corresponding to XDR and SQL XML (all of whichbegin with urn:schemas-microsoft-com:, followed by one of xml-data, datatypes, xml-sql,
or xml-updategram) that identify schema contents or annotations, respectively Second, there are
external schema references, which we will explain next And finally, everything else – which are treated
as ordinary namespace names
External schema references are distinguished from ordinary namespace URIs by beginning with thestring x-schema: Every such namespace URI is treated as a reference to a schema at the file locationlisted after the colon The external schema will be loaded, and all its ElementType and
AttributeType declarations made available to the schema that imported it (and in fact, all of theschemas currently being processed)
The following two schemas demonstrate the concept:
<! ch15_ex27.xdr >
<Schema xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<ElementType name="Customer" sql:relation="Customers">
<element type="x:Order" xmlns:x="x-schema:ch15_ex28.xdr">
<sql:relationship key-relation="Customers" key="CustomerID"
foreign-relation="Orders" foreign-key="CustomerID" />
</element>
</ElementType>
</Schema>
Trang 11<Order CustomerID="ALFKI" OrderID=""/>
<Order CustomerID="ALFKI" OrderID=""/>
<Order CustomerID="ALFKI" OrderID=""/>
</Customer>
<Customer>
<Order CustomerID="ANATR" OrderID=""/>
<Order CustomerID="ANATR" OrderID=""/>
</Customer>
<! >
exactly as if there had been only one schema
The second part of using namespaces in XML Views is the sql:target-namespace annotation Thesql:target-namespace annotation is used on the Schema element, and declares that all the top-leveldeclarations in the schema will go into that namespace URI This annotation can be used on a schema
by itself; but it is most commonly used in conjunction with external schemas, creating a web of schemas,one for each namespace URI
If we modify the second schema above to use a target namespace:
<y:Order xmlns:y="your namespace" CustomerID="ALFKI" OrderID=""/>
<y:Order xmlns:y="your namespace" CustomerID="ALFKI" OrderID=""/>
<y:Order xmlns:y="your namespace" CustomerID="ALFKI" OrderID=""/>
</Customer>
<Customer>
<y:Order xmlns:y="your namespace" CustomerID="ANATR" OrderID=""/>
<y:Order xmlns:y="your namespace" CustomerID="ANATR" OrderID=""/>
</Customer>
<! >
Trang 12Note that the prefix used in the schema is not necessarily preserved in the XML result Also note that,although the Order element is placed into a namespace, none of its attributes are This is consistentwith the normal interaction between attributes and namespace declarations If you require an attribute
to be placed in the target namespace, declare it at the top-level of the schema
We should note that the use of namespaces in XPath is currently limited to templates XPath usesnamespace prefixes, so it requires those prefixes to be bound to namespace URIs Currently SQL Serverdoes not provide a way to perform this binding in a URL, so the binding must occur in XML (usingordinary namespace declarations)
Structural Recursion
Unfortunately, XML Views currently do not directly support recursion The reason is that creatingrecursive hierarchies usingFOR XML EXPLICIT (which XPath uses) requires advance knowledge of thedepth of the hierarchy to construct the query This problem is demonstrated by the SQL query
FROM Employees E1 JOIN Employees E2 ON E1.EmployeeID = E2.ReportsTo
WHERE E1.ReportsTo = NULL
FROM Employees E1 JOIN Employees E2 ON E1.EmployeeID = E2.ReportsTo
JOIN Employees E3 ON E2.EmployeeID = E3.ReportsToWHERE E1.ReportsTo = NULL
ORDER BY 3, 4, 5FOR XML EXPLICIT
This limitation of XML Views prevents the use of recursive schemas like:
Trang 13because the EXPLICIT query needed is data-dependent Until XML Views provides explicit support forrecursion, an alternative method is required.
The natural first attempt, an almost-recursive schema like the one below, also does not work Let's look
at this to see why:
<! This schema will not work! >
The problem with this schema is that the join relationship from the table to itself, a so-called self-join, is
also not supported by XML Views at the time of this writing
However, all is not lost! Using a little imagination, it is possible to create recursive hierarchies Onesolution is to alias the table using a SQL view, then use that view in the annotated schema The
following example demonstrates this technique using the Employees table in the Northwind database.First, prepare a SQL view that mirrors the Employees table:
CREATE VIEW Managers AS SELECT * FROM Employees
Then, use the SQL view in the schema (ch15_ex31.xdr):
Trang 14Updategrams, XPaths, and ordinary SQL queries can be executed from XML templates, and the resultsfrom these queries substituted into the XML template Combined with other standard XML processingtechniques (such as XSL), these query languages provide a powerful way to transport and present XMLdata on the Web.
Trang 17If you are an enterprise Java developer who specializes in writing database applications using the JDBCAPI, you have probably had to confront the thorny issue of extending your applications to today'spervasive computing environment Nowadays, people expect to be able to access mission-critical dataanytime, anywhere, and from any device, regardless of what data access API is being used to
manipulate the underlying data source The challenge of the enterprise Java developer is to create JDBCapplications that allow platform-neutral, device-independent access to data By XML-enabling yourJDBC applications, you can accomplish this Here is the good news; it's easier than you might think
How XML Enhances JDBC (and vice versa)
When you combine XML with J2EE (Java 2, Enterprise Edition) technologies and standard Internetprotocols (such as HTTP), you can write enterprise applications that provide universal data access toJDBC data sources with a minimal amount of coding With XML, XSLT, and JDBC, you can designscalable and extensible architectures that facilitate device-independent data delivery in J2EE
applications This allows end users to access your data using web browsers, WAP devices, PDAs, or anyother current or future device that renders content using an XML-based markup language
Moreover, combining XML and JDBC facilitates the creation of web services using J2EE Web services
are HTTP applications that provide an application programming interface rather than a user interface With
web services, your trading partners can integrate your business processes and data with their
applications, regardless of which hardware platform and operating system they are built on, or
programming language that they are written in
Trang 18This chapter will give you some practical, hand-on examples of how to integrate XML with JDBC inyour J2EE applications in a manner that facilitates device-and-platform independent universal dataaccess in today's pervasive computing environment Specifically, it will cover two scenarios:
❑ Generating XML from a JDBC data source: We will walk through the construction of a simpleXML gateway architecture for JDBC This architecture contains software components thatallow you to execute SQL statements against arbitrary JDBC data sources, returning the resultsets as well-formed XML data structures that can then be consumed by any application withXML parsing capabilities Next, we will show you how to add server-side XSLT processingcapabilities to this architecture to illustrate how easy it is to transform the XML-serializedJDBC result set, to a mark-up language that targets a particular device, such as a web browser
❑ Using XML to update a JDBC data source: In this scenario, we will show you how to use
WebRowSets, an emerging Java technology, to create distributed JDBC applications that useXML to marshal disconnected Result sets between remote machines Please note that, as ofthis writing, the WebRowSet binaries are still in "early access" status, and could change
slightly before becoming part of the core API
Software Needed for This Chapter
Before getting started, you should make sure that you install and configure the core software needed towork through the examples provided in the chapter This software includes JDK 1.3, the Xalan XSLTprocessor for Java, Tomcat 3.1, and a relational database system with a JDBC driver For the most part,the code samples in this chapter will compile and run on virtually any system for which a reasonableimplementation of the Java virtual machine has been ported Since we developed and tested thesesamples on Windows NT 4.0, most of the examples in this chapter are NT-centric
JDK 1.3
The first piece of software needed is JDK 1.3 You can download this free of charge from
http://java.sun.com When you download it, ensure that you select the correct installer for the operatingsystem you are using If you are using NT, for example, you will download and run the InstallShieldself-extracting setup program I also recommend that you download the JDK documentation, which isavailable as a separate download While you can browse this documentation on Sun's Java web site, youwill find it infinitely more convenient to have it available on your local file system
One point of clarification: while we recommend JDK 1.3, we have also tested the code in this chapter
on JDK 1.2.2 This is important because JDK 1.3 has not been ported to as many platforms as theubiquitous JDK 1.2.2 One word of caution: if you do decide to use JDK 1.2.2, make sure you downloadthe JNDI (Java Naming and Directory Interface) reference implementation The WebRowSet examplescovered later require JNDI While JDK 1.3 includes JNDI, JDK 1.2.2 does not, and you must add this as
a separate download We will discuss this in more detail later in the chapter
Xalan XSLT Processor for Java
The next piece of software we will use is Xalan for Java version 1.2 Xalan is an open-source XSLTprocessor that is maintained by the Apache Group You can download it from http://xml.apache.org.After downloading and unpacking the xalan-j_1_2_D02.zip archive, locate the xalan.jar andxerces.jar (the Xerces XML parser) archives and copy them to the \jdk1.3\lib directory
Trang 19If you don't want to use Xalan, or you would like to try another XSLT processor, there are severalquality XSLT processors implemented in Java Examples include:
❑ IBM LotusXSL (http://alphaworks.ibm.com/tech/LotusXSL)
❑ James Clark's XT package (http://www.jclark.com/xml/xt.html)
Software Needed to Implement Rowsets
To run the sample distributed JDBC application, you'll need to download the Java packages used toimplement the WebRowSet framework This framework provides a transparent mechanism for
serializing the data, metadata, and properties of a JDBC result set to XML for transportation andmanipulation by a remote application across the network We will cover this framework in more detaillater The packages needed to use the WebRowSet framework include the sun.jdbc.rowset andjavax.sql packages, and the JNDI reference implementation We'll cover the framework in moredetail later; for now, just follow the instructions below to download and install the software
The sun.jdbc.rowset Package
To download this package, point your browser at:
http://developer.java.sun.com/developer/earlyAccess/crs/ This is "early access" technology, so youmust create a free account with the Sun Java Developer Connection if you haven't already done so Thesamples in this chapter have been tested with the "early access 4" release Once you have downloadedthe rowset-1_0-ea4.zip archive, locate the rowset.jar file and place it in the C:\jdk1.3\libdirectory
The WebRowSet implementation contained in this package is an experimental,
unsupported technology Therefore, it may change before it becomes an official part of
the Java platform Please do not use this technology in a production application until
it is released as a final, stable product.
The javax.sql Package
The JDBC 2.0 API includes two packages: java.sql, which contains the JDBC 2.0 core API, andjavax.sql, which contains the JDBC 2.0 standard extension API The java.sql package is includedwith the JDK, so it should already be on your system Since the WebRowSet class uses the JDBC 2.0standard extension API, we'll need the javax.sql package, which is provided as a separate download
To download this package, point your browser at http://java.sun.com/products/jdbc/download.html,and select the JDBC 2.0 Optional Package Binary Download the jdbc2_0-stdext.jar archive, andplace it in the C:\jdk1.3\lib directory
The JNDI Reference Implementation
The WebRowSet class uses JNDI (Java Naming and Directory Interface) If you installed JDK version1.3, you can skip this step JDK 1.3 ships with JNDI If you are using JDK 1.2.2, you must download theJNDI reference implementation from Sun's web site To do so, point your browser at
http://java.sun.com/products/jndi/index.html Download the jndi1_2_1.zip archive and unpack it;locate the jndi.jar file, and place it in your CLASSPATH
Trang 20Tomcat 3.1
Since all of the sample applications covered in this chapter are implemented at least in part using theJava servlet API, you will need to install and configure a servlet container on your system The
examples provided should work in any servlet container that supports the Java servlet API version 2.2
or higher We recommend Tomcat 3.1, the open-source servlet and JSP reference implementationdeveloped by the Apache Software Foundation This is a lightweight, high performance servlet
container that is easy-to-use, implements the standard religiously (it is, after all, the reference
implementation), and includes a lightweight HTTP listener that eliminates the need to install a separateweb server To qualify this comment, the HTTP listener is useful for unit-testing applications In aproduction environment, you should use a commercial-quality web server with the appropriateconnector Tomcat provides connectors for Apache, IIS, and Netscape/iPlanet Enterprise Server Since
it is implemented in Java, Tomcat will run on a variety of different platforms Here are the installationsteps for Windows NT 4.0:
❑ Download jakarta-tomcat.zip from http://jakarta.apache.org
❑ Install it by unpacking the zip archive into a directory on your hard drive
❑ Modify the jakarta-tomcat\bin\tomcat.bat file to point the JAVA_HOME variable to thedirectory in which you installed JDK 1.3 This variable assignment does not exist in the batchfile, so you will need to add it For example, if you installed the JDK on the C drive, add thisvariable assignment to the file: set JAVA_HOME=C:\jdk1.3
❑ You also want to change the jakarta-tomcat\bin\tomcat.bat file to add the rowset,JDBC standard extensions, Xerces, and Xalan code base to Tomcat's CLASSPATH To do so,insert the following code on or about line 35 of tomcat.bat (this assumes that you put theJAR files, as recommended, in the jdk1.3\lib directory):
rem This is an existing line in the batch file Look for it to find
rem the right spot to add your additional JARs to the CLASSPATH:
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\lib\tools.jar
rem Start adding your additional jars here:
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\lib\rowset.jar
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\lib\jdbc2_0-stdext.jar
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\lib\xerces.jar
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\lib\xalan.jar
❑ Run the jakarta-tomcat\bin\startup.bat to start Tomcat
❑ Point your browser to http://127.0.0.1:8080 By default, Tomcat's HTTP server listens on port
8080 to preclude any conflict with a web server that might already be installed on your systemand listening on port 80 Of course, you can change the port assignment, if desired, by editingthe server.xml configuration file (see the Tomcat documentation for more details) Whenyou hit this URL, you will see the Tomcat home page
If you are using a UNIX variant, the installation and configuration steps are similar, with a few keydifferences Instead of downloading the ZIP archive, you want to download and unpack the tararchive In addition, you will need to modify the tomcat.sh UNIX shell script instead of the
tomcat.bat batch file Refer to the Tomcat documentation for additional information
Trang 21At the end of the chapter, we will cover all of the steps required to package our sample applications fordeployment to Tomcat or any other J2EE-compliant servlet container In the meantime, you might want
to download the web application archive provided with the sample code for this chapter from our website; details on how to get all of the code for this book is supplied in the support and errata appendix.This will allow you to test the examples while you are going through the chapter To do so, followthese steps:
❑ If Tomcat is already running, stop it using the shutdown.bat batch file located in the
In addition to the HTML and the compiled binaries, this archive also includes all of the source codediscussed in this chapter
A JDBC Data Source and Driver (Oracle, SQL Server, etc.)
Finally, you will need to have access to a database with a JDBC driver The examples are writtengenerically enough to work with a variety of different relational database products Most databaseproducts on the market today include a JDBC driver The three that we will use in this chapter areOracle 8i via the Oracle thin JDBC driver, and Microsoft SQL Server 7.0 and Microsoft Access 97, bothvia the JDBC-ODBC Bridge
Trang 22The Oracle JDBC driver is typically packaged in a file called classes111.zip This file comes withany Oracle installation, so your Oracle database administrator will be able to provide it for you Youcan also download it from http://www.oracle.com The JDBC-ODBC Bridge ships with the JDK.
To preclude any problems from occurring, you want to ensure that the JDBC driver you will use isadded to the CLASSPATH If you are using the JDBC-ODBC Bridge, this was taken care of when youinstalled the JDK, so you don't need to worry about it If your database does not have a JDBC driver(or you are unsure), you can simply use the JDBC-ODBC Bridge (assuming that the database productprovides an ODBC driver, as most do) Please consult your specific database product's documentationfor more information
Generating XML from JDBC
As we touched on earlier, XML and JDBC complement each other very well Using these two
technologies, you can create "universal data access" applications that can run on a variety of differentJ2EE-compliant application servers and access a variety of different data sources It gives you the best ofall worlds The use of XML allows you to make your data and metadata available to virtually anyapplication, regardless of how it was written or the type of platform on which it runs The use of Javaand the J2EE APIs gives the application developer platform and vendor freedom of choice; a variety ofdifferent vendors have created J2EE-compliant application servers that run on a variety of differenthardware and OS combinations A short list includes ATG, BEA Systems, IBM, and the iPlanet Sun-Netscape Alliance The use of JDBC as the data access API allows you to leverage decades worth ofrelational data technology and thought leadership
The challenge, then, is to create an architecture that allows you to extract data from a JDBC datasource, serialize it to XML, and send it to the requesting client, using XSLT as appropriate to createoutput that targets a particular device For extensibility purposes, this architecture should be designed in
a manner that abstracts the process of accessing the data source via JDBC and serializing the Result set
as XML, thereby shielding the application developer from these details, and promoting code reuse Toillustrate this, we will create a simple XML gateway architecture for JDBC
Our Simple XML Gateway Architecture for JDBC
The heart of our XML gateway architecture for JDBC is the JDBC2XML class This class controls access
to the JDBC data source Briefly, it executes a SQL statement against the specified JDBC data source,serializes the returned JDBC result set as XML, and returns this XML document to the calling client Inour architecture, the JDBC2XML class will be reused by two Java servlets: the XMLDataGateway servlet and the JDBC2HTML servlet The XMLDataGateway servlet provides a generic XML-over-HTTPinterface to JDBC data sources for XML-enabled applications The JDBC2HTML servlet returns JDBCresult sets as HTML to web browsers using the specified XSL stylesheet This servlet essentially acts as afilter; when an HTTP user agent submits an HTTP GET or POST request to an XSL stylesheet, therequest is delegated to the JDBC2HTML servlet for handling The following figure shows this
architecture:
Trang 23A Simple XML Gateway Architecture for JDBC
XML-enabled Application
XMLDataGateway
Servlet
Web browser
HTML over HTTP
XSL Stylesheet
Delegated to
JDBC2HTML Servlet
JDBC2XML Class
XSLT
In-process
call
In-process call
XML serialized resultset
XML serialized resultset
JDBC
JDBC Data Source
This section will walk you through creating and using this architecture Specifically, it will show youhow to do the following:
❑ Develop the JDBC2XML class
❑ Develop the XMLDataGateway servlet
❑ Query a JDBC data source using the XMLDataGateway servlet
❑ Develop the JDBC2HTML servlet
❑ Write an XSL stylesheet that defines HTML presentation logic for our <resultset/> XMLschema
❑ Query a JDBC data source using the JDBC2HTML servlet
Trang 24The JDBC2XML Class
The class encapsulates the functionality required to query a JDBC data source and return the results ofthat query as a well-formed XML document Essentially, it executes a SQL statement against thespecified JDBC data source, serializes the returned JDBC result set as XML, and returns this XMLdocument to the calling client as a string Create the JDBC2XML.java file and enter the following code:
To accomplish this, the JDBC2XML class implements several different methods These methods include:
❑ Methods that apply XML encoding rules, including the encodeXML() method
❑ A method that serializes a JDBC result set to XML, the writeXML() method
❑ The method that brings everything together by executing the search and returning the results
as XML (the execute() method)
This section will show you how to implement each method
Applying XML Encoding Rules to the Result Set Data
The encodeXML() method is a generic method that allows you to apply XML encoding rules to certainspecial characters A well-formed XML document with element or attribute values containing thesespecial characters must be specially encoded to escape them out Otherwise, an XML parser will not beable to process the document This table shows those characters and their encoded values:
Character Encoded value
The encodeXML() method simply does a search-and-replace operation on the passed-in string,
replacing instances of the special characters with their encoded equivalent This method will be used bythe writeXML() method to ensure that any data retrieved from the database is encoded properlybefore being serialized to XML:
Trang 25String encodeXML(String sData)
{
String[] before = {"&","<",">","\"", "\'"};
String[] after = {"&","<",">",""", "'"};
if(sData!=null)
{
for(int i=0;i<before.length;i++){
sData = Replace(sData, before[i], after[i]);
}}
String Replace(String content, String oldWord, String newWord)
Serializing the Result Set's Metadata and Data as XML
The next step is to add code to our JDBC2XML class that serializes a JDBC result set to XML Toaccomplish this, we need to do two things: design an XML data structure that encapsulates the data andmetadata of a result set, and implement the writeXML() method that performs the actual serialization
Designing the <resultset> XML Structure
The first step is to define an XML data structure that will represent the serialized state of our JDBCresult set For simplicity, we will create a DTD-less document that can be parsed by non-validatingXML parsers The root element is the <resultset> element This element contains two sub-elements:
a <metadata> element, and a <records> element
The <metadata> element contains a <field> element for each database field This element containstwo attributes: a name attribute, and a datatype attribute The <records> element contains a
<record> element for each row in the result set The <record> element also contains a <field>element for each column This code fragment shows the structure of our <resultset> XML
Trang 26<record>
<field name="field name goes here">
field's value goes here
</field>
</record>
</records>
</resultset>
Implementing the writeXML() Method
The writeXML() method serializes the specified JDBC result set as an XML document that conforms
to the structure defined above The first action it performs is to create a StringBuffer that containsthe <?xml?> processing instruction and the <resultset> root element We will use this
StringBuffer object to hold our output Next, it enumerates through the result set's metadata,creating a <field> element for each column Finally, it enumerates through each record of the resultset, creating a <record> element that contains a <field> element for each column Field values arepre-processed with the encodeXML() method defined above to ensure compliance with XML encodingrules Once we have looped through the entire result set, we terminate the <resultset> element, andreturn the XML document:
String writeXML(ResultSet rs)
{
StringBuffer strResults = new StringBuffer
("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n<resultset>\r\n");try
{
ResultSetMetaData rsMetadata = rs.getMetaData();
int intFields = rsMetadata.getColumnCount();
strResults.append("<metadata>\r\n");
for(int h =1; h <= intFields; h++){
strResults.append("<field name=\"" + rsMetadata.getColumnName(h) +
"\" datatype=\"" + rsMetadata.getColumnTypeName(h) + "\"/>\r\n");}
strResults.append("</metadata>\r\n<records>\r\n");
while(rs.next()){
}}catch(Exception e) {}
strResults.append("</records>\r\n</resultset>");
return strResults.toString();
}
}
Trang 27Executing the Query
The execute() method brings it all together by executing a query against a JDBC data source andreturning the results as an XML document It takes five input parameters:
String output = new String();
The first step is to register and instantiate the JDBC driver Next, we will connect to the database andcreate a statement object After that, we will execute the SQL statement using the statement object'sexecuteQuery() method This will return a result set We will then serialize the result set to XMLusing the writeXML() method we created above:
Now our JDBC2XML reusable class is complete, and we can start using it in our sample applications
The XMLDataGateway Servlet
The XMLDataGateway servlet uses the JDBC2XML class to provide a generic XML-over-HTTP interface
to JDBC data sources In this section, we will show how to implement and use this servlet
Trang 28Implementing the Servlet
To implement the XMLDataGateway servlet, we will write a Java class that subclasses the
javax.servlet.http.HttpServlet class We will also override the doGet() and doPost()methods to handle HTTPGET and HTTPPOST requests
Overriding the doGet() Method
The doGet() method allows the XMLDataGateway servlet to respond to HTTP GET requests The code
in this method is actually simple First, we will set the MIME type to "text/xml." That way, requestingHTTP user agents will know that the response sent should be handled as an XML document Next, wewill get a reference to the PrintWriter object that enables us to write a response back to the client.Finally, we'll instantiate the JDBC2XML class and call the execute() method This method will returnthe XML-serialized result set, which we will pass immediately to the HTTP response stream's
PrintWriter We will obtain the SQL and JDBC connection information needed by the execute()method from the HttpServletRequest object, which encapsulates key-value pairs obtained from theURL's query string If this seems a little confusing right now, don't worry; it will become much clearerwhen we run a sample application
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException
}
Overriding the doPost() Method
The next step is to override the doPost() method In this particular servlet, we will handle HTTPPOSTs the same way we handle HTTP GETs Therefore, our doPost() implementation will simplymake a call to doGet()
public void doPost(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException
{
doGet(request, response);
}
}
Trang 29That's all there is to writing the XMLDataGateway servlet Now, you would compile the Java sourceinto bytecode and package it for deployment to a J2EE-compliant servlet container We will cover thisprocess in detail at the end of the chapter once we have completed the entire application In themeantime, we will walk through a few examples of how to use the XMLDataGateway servlet, using thepre-built jdbcxml.war web application downloaded from the Wrox web site For more information onhow to deploy jdbcxml.war to Tomcat, please refer to the section in this chapter on installing andconfiguring Tomcat.
Developing an HTML Form Interface
In order to test the XMLDataGateway servlet, we must create a user interface for it Since the servlet is
an HTTP application, we will create a simple HTML form that allows you to test it from a web browser
We will save it in an HTML file, and name that file xmlsqlquery.html
The XMLDataGateway servlet of course will be the action handler for the HTML form, and the formwill use HTTP POST as the request method The form contains five fields, each corresponding to theassociated request parameter expected by the servlet Here's the source listing for the
XMLDataGateway's HTML front end For brevity purposes, only the HTML form itself is shown,omitting the HTML opening and closing tags and any other tags the file might have:
<form action="/jdbcxml/servlet/XMLDataGateway" method="POST">
<td align="right"><font face="Arial">password </font></td>
<td><font face="Arial"><input type="password"
size="50" name="pwd"></font></td>
</tr>
<tr>
<td align="right"><font face="Arial">SQL Statement:</font></td>
<td><textarea name="sql" rows="10" cols="50"></textarea></td>
Trang 30Using the XMLDataGateway Servlet
As we mentioned earlier, the XMLDataGateway servlet can be used from any HTTP client that knowshow to parse and render (or manipulate) well-formed XML This section will discuss two scenarios forusing the XMLDataGateway servlet: from a web browser, and from a Win32 application
Using XMLDataGateway from a Web Browser
Now we are ready to start using the XMLDataGateway servlet First, start Tomcat if it isn't alreadyrunning Then, point your browser at http://127.0.0.1:8080/jdbcxml/xmlsqlquery.html Since the resultswill come back as XML, I recommend you use a browser that knows how to consume and display well-formed XML, such as Microsoft Internet Explorer 5.x or higher On the HTML form, type in the name
of the JDBC driver you want to use, the URL of the JDBC data source, the user ID and passwordrequired to log onto the database server, and the SQL statement Then, click the Submit Query button
to execute the query
To give you a specific example, we will walk through a search of a Microsoft Access database Tofacilitate this, we have provided a sample MS-Access database as part of the chapter's sample codedownload This database is named contacts.mdb, and is located in the
\Chapter16\jdbcxml\sql directory
Prior to running through this example, we need to set up this Access database as a System DSN usingthe Windows NT Control Panel ODBC applet After launching this applet, you will see the ODBCData Source Administrator Click on the Add button, and you will see this dialog:
Trang 31Select the Microsoft Access driver, and click on Finish You will see this dialog:
For the data source name, type in contacts Click on the Select button, and browse to the location ofthe contacts.mdb file on your local system Once you have completed that, click on OK You shouldnow be back to the ODBC Data Source Administrator, and it should show your new contacts SystemDSN added to the list:
Trang 32Now we are ready to execute a query On the xmlsqlquery.htmlform, type in the followinginformation:
❑ The fully qualified class name of the Sun JDBC-ODBC:
driver:(sun.jdbc.odbc.JdbcOdbcDriver)
❑ The Contacts database's JDBC URL (jdbc:odbc:contacts)
❑ Since the Contacts database does not implement any security, you can simply leave the user
ID and password blank
❑ For the SQL statement, type in SELECT * FROM contacts
The completed form should look like this:
Trang 33To execute the query, click on the Submit Query button Your results should look like this:
To give you a more advanced example, we will walk through a search of an Oracle 8i database We willuse the Oracle thin driver This example should work with any Oracle installation, since it merelyqueries the user_tables entity To make the connection, we'll type in the following information:
❑ The fully qualified class name of the Oracle JDBC driver:
(oracle.jdbc.driver.OracleDriver) You must ensure that the Oracle JDBC driver is inTomcat's CLASSPATH To add it, please view the Tomcat setup instructions that were coveredearlier in this chapter
❑ The Oracle database's JDBC URL, using the following form:
jdbc:oracle:thin:@oraclehostname:port:oracledbname, where oraclehostname
is the name of the server on which the Oracle database resides, port is the IP port on which
to connect to the Oracle database, and oracledbname is the name of the particular database
to query
❑ The user ID and password with which to log onto the Oracle database server
Trang 34Finally, we'll type in the SQL statement This example is a simple query of the Oracle user_tablesentity Here's what the complete query looks like:
When we execute the query, the servlet sends the XML-serialized result set showing the query results.This is what it looks like in MS Internet Explorer 5.x:
Trang 35As we have mentioned before, if you don't have access to Oracle, you can use the XMLDataGatewayservlet to query any database product for which a JDBC driver has been written To preclude anyproblems that might occur when testing it with another database product, please ensure that the JDBCdriver for this database is added to Tomcat's CLASSPATH In addition, if you are using a desktopdatabase product such as Microsoft Access, many of these products allow you to create databases that
do not require verification of user credentials If this is the case, then you simply leave the user ID andpassword fields blank You should also note that the JDBC URL format is driver-dependent Therefore,
if you are using a database other than Oracle, please consult the product's documentation for
information on how to form a valid JDBC URL
Using the XMLDataGateway Servlet from Other XML-Enabled Applications
As we mentioned before, one of the great advantages of using the XMLDataGateway servlet is that itallows you to extend the availability of your JDBC data source to non-Java applications For example,one of your trading partners might use a system that is implemented as a Win32 application written inVisual C++ Your internal systems might be built on the J2EE architecture, using JDBC to access anOracle database server running on Solaris
One of the easiest ways to integrate these two systems over the Internet is via XML-over-HTTP, whichour XMLDataGateway servlet implements Your trading partner's Win32 application can be modified touse MSXML to execute SQL statements against your Oracle database via HTTP GET From there, it canperform any necessary integration steps
Note: If you are planning to make your data available over the Internet via
XML-over-HTTP, please ensure that you attend to the security details For example, ensure
that default passwords are changed for database administrator accounts, access
control lists are properly set, and SSL encryption is used.
To show you a simple example of this process, we will use the Microsoft XML Notepad to execute thesame Microsoft Access query we covered in the previous section You can download Microsoft XMLNotepad from http://msdn.microsoft.com/xml/notepad/
After you have installed XML Notepad, launch the application, click on File in the menu bar, and thenclick on Open You'll see a dialog box that looks like this:
Select the From URL radio button, and then type in the following URL Yes, it is that long:
http://127.0.0.1:8080/jdbcxml/servlet/XMLDataGateway?driver=sun.jdbc.odbc.JdbcOdbcDriver&jdbcurl=jdbc:odbc:contacts&sql=select+*+from+contacts
Trang 36In this example, you'll notice that we are using HTTP GET instead of HTTP POST The input parametersthat the servlet takes are placed as ampersand-delimited key-value pairs in the URL's query string Oncethe query is executed, XML Notepad will display the results as follows:
Summary
In this section, we walked through the creation of the XMLDataGateway servlet, a simple example ofhow you can create an architecture-neutral XML-over-HTTP gateway to your JDBC data sources In thenext section, we will take it a step further by extending this architecture to perform device-specifictransformations of JDBC data using XML and XSLT
Trang 37The JDBC2HTML servlet is designed as a filter; in other words, the servlet is not invoked directly.Instead, the servlet container is configured to dispatch requests for URLs with a particular mapping tothis servlet for handling In the case of the JDBC2HTML servlet, we will configure the servlet container
to pass any URL requests for files ending in xsl to the JDBC2HTML servlet for execution This ishow the servlet will know which XSL stylesheet to use for the XSLT operation If this sounds confusing,don't worry; we will cover how this process works in detail as the chapter proceeds
This section will show you how to implement this framework, specifically the following tasks:
❑ Writing the servlet itself
❑ Writing a generic XSL stylesheet that transforms the XML-serialized result set into an HTMLtable
❑ Using the JDBC2HTML servlet to query a Microsoft SQL Server database
Implementing the JDBC2HTML Servlet
As with the XMLDataGateway servlet, we will implement the JDBC2HTML servlet by writing a Javaclass that subclasses the javax.servlet.http.HttpServlet class We will also override thedoGet() and doPost() methods to handle HTTP GET and HTTP POST requests respectively Since
we are using the Xalan XSLT processor in the servlet, we will import the org.apache.xalan.xsltpackage We will also import the org.xml.sax.SAXException class, which is thrown by the XercesSAX parser (the underlying parser used by Xalan) if either the XML document or the XSL stylesheet isnot well formed:
Overriding the doGet() Method
The next step is to override the doGet() method for HTTP GET request handling Since the
JDBC2HTML servlet is a filter, the first order of business is to determine the physical file location of therequested stylesheet It first checks the PATH_INFO environment variable If it is Null, the servletassumes that it was invoked as a result of a direct URL request for an XSL stylesheet (for example,http://hostname/dir/myStylesheet.xsl), and obtains the stylesheet's real path by passing the
SCRIPT_NAME environment variable (obtained via the getServletPath() method call) to the servletcontext's getRealPath() implementation Otherwise, it uses the PATH_INFO (for example, thePATH_INFO for http://hostname/servlet/JDBC2HTML/dir/myStylesheet.xsl is
/dir/myStylesheet.xsl), and gets the PATH_INFO 's real path via the Request object's
getPathTranslated() method
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException
{
Trang 38Finally, it will use the Xalan XSLT processor to transform the results of the query to HTML using therequested XSL stylesheet file, and place the output in the HTTP response stream:
try
{
XSLTProcessor processor = XSLTProcessorFactory.getProcessor();
processor.process(new XSLTInputSource(newjava.io.StringReader(output)), new XSLTInputSource("file:///" +qryDoc), new XSLTResultTarget(out));
Overriding the doPost() Method
The next step is to override the doPost() method As with the XMLDataGateway servlet, the
JDBC2HTML servlet will handle HTTP POSTs the same way we handle HTTP GETs Therefore, ourdoPost() implementation will simply make a call to doGet()
public void doPost(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException
{
doGet(request, response);
}
}
That's all there is to writing the JDBC2HTML servlet While a bit more complex than the
XMLDataGateway servlet, it is still straightforward Moreover, the same concepts could be easilyapplied to other device types, such as a WAP phone The only difference would be in the MIME type(for example, text/vnd.wap.wml vs text/html), the output syntax (WML vs HTML), and thedisplay constraints of WAP devices vis-à-vis web browsers
Trang 39Now, you would compile the Java source code into bytecode and package it for deployment to a compliant servlet container Part of this packaging process would include creating a mapping thatinstructs the servlet container to hand off all requests for xsl files to the JDBC2HTML servlet We willcover this process in detail at the end of the chapter In the meantime, we will walk through a fewexamples of how to use the JDBC2HTML servlet using the jdbcxml.war web application downloadedfrom our web site, and deployed to Tomcat in an earlier section.
to match the root element of the document:
The Resultset Template
The next template is for the top-level <resultset> element This template does two things First, itsets up the basic structure of the HTML document Second, it uses the <xsl:apply-templates>element at the appropriate spots to apply the templates for the <metadata> element (which will bedisplayed as the table's heading) and the <records> element (which will be displayed as the tablebody) In the case of the <records> element, the //resultset/records notation tells the XSLTprocessor to match any <records> element that is a descendant of the <resultset> element:
Trang 40The Metadata and Metadata Field Templates
The next two templates set up the table header row from the <metadata> element and its <field>child elements The meta-data template creates the table row The field template creates a table cell foreach field:
The Records and Record Templates
The next two templates create a table row for each record, with a table cell containing the data for eachfield:
The Error Template
Finally, we have a template to handle any errors that might occur As you might recall, the
JDBC2XML's execute() method returns an <error> element containing information from anyexception that is thrown within that method This template ensures that this information is displayed in