A WebRowSet
object is very special because in addition to offering all of the capabilities of a CachedRowSet
object, it can write itself as an XML document and can also read that XML document to convert itself back to a WebRowSet
object. Because XML is the language through which disparate enterprises can communicate with each other, it has become the standard for Web Services communication. As a consequence, a WebRowSet
object fills a real need by enabling Web Services to send and receive data from a database in the form of an XML document.
The following topics are covered:
The Coffee Break company
has expanded to selling coffee online. Users order coffee
by the pound from the Coffee Break Web site. The price list
is regularly updated by getting the latest information from
the company's database. This section demonstrates how to send the price data as an XML document with a WebRowSet
object and a single method call.
You create a new WebRowSet
object with the default
constructor defined in the reference implementation,
WebRowSetImpl
, as shown in the following line of code:
WebRowSet
priceList = new WebRowSetImpl();
Although the priceList
object has no data yet, it has the default properties of a BaseRowSet
object. Its SyncProvider
object is at first set to the RIOptimisticProvider
implementation, which is the default for all disconnected
RowSet
objects. However, the WebRowSet
implementation
resets the SyncProvider
object to be the RIXMLProvider
implementation.
You can use an instance of RowSetFactory
, which is created from the RowSetProvider
class, to create a WebRowSet
object. See Using the RowSetFactory Interface in Using JdbcRowSet Objects for more information.
The Coffee Break headquarters
regularly sends price list updates to its web site. This information on WebRowSet
objects will show one way you can send the latest price list in an XML document.
The price list consists of the data in the columns COF_NAME
and PRICE
from the table COFFEES
. The following code
fragment sets the properties needed and populates
the priceList
object with the price list data:
public void getPriceList(String username, String password) { priceList.setCommand("SELECT COF_NAME, PRICE FROM COFFEES"); priceList.setURL("jdbc:mySubprotocol:myDatabase"); priceList.setUsername(username); priceList.setPassword(password); priceList.execute(); // ...
At this point, in addition to the default properties,
the priceList
object contains the data in the COF_NAME
and PRICE
columns from the COFFEES
table and also the metadata
about these two columns.
To write a WebRowSet
object as an XML document, call the method writeXml
. To read that XML document's contents into a WebRowSet
object, call the method readXml
. Both of these methods
do their work in the background, meaning that everything,
except the results, is invisible to you.
The method writeXML
writes the WebRowSet
object that
invoked it as an XML document that represents its current
state. It writes this XML document to the stream that you
pass to it. The stream can be an OutputStream
object, such
as a FileOutputStream
object, or a Writer
object, such as
a FileWriter
object. If you pass the method writeXML
an
OutputStream
object, you will write in bytes, which can
handle all types of data; if you pass it a Writer
object,
you will write in characters. The following code
demonstrates writing the WebRowSet
object priceList
as an XML document to the FileOutputStream
object
oStream
:
java.io.FileOutputStream oStream = new java.io.FileOutputStream("priceList.xml"); priceList.writeXml(oStream);
The following code writes the XML document representing
priceList
to the FileWriter
object writer
instead of to an OutputStream
object. The FileWriter
class
is a convenience class for writing characters to a file.
java.io.FileWriter writer = new java.io.FileWriter("priceList.xml"); priceList.writeXml(writer);
The other two versions of the method writeXML
let you
populate a WebRowSet
object with the contents of a
ResultSet
object before writing it to a stream. In the
following line of code, the method writeXML
reads the
contents of the ResultSet
object rs
into
the priceList
object and then writes priceList
to the
FileOutputStream
object oStream
as an XML document.
priceList.writeXml(rs, oStream);
In the next line of code, the writeXML
methodpopulates
priceList
with the contents of rs
, but it
writes the XML document to a FileWriter
object instead of
to an OutputStream
object:
priceList.writeXml(rs, writer);
The method readXml
parses an XML document in order to
construct the WebRowSet
object the XML document describes.
Similar to the method writeXml
, you can pass readXml
an
InputStream
object or a Reader
object from which to read
the XML document.
java.io.FileInputStream iStream = new java.io.FileInputStream("priceList.xml"); priceList.readXml(iStream); java.io.FileReader reader = new java.io.FileReader("priceList.xml"); priceList.readXml(reader);
Note that you can read the XML description into a new
WebRowSet
object or into the same WebRowSet
object that
called the writeXML
method. In the scenario, where the
price list information is being sent from headquarters to
the Web site, you would use a new WebRowSet
object, as
shown in the following lines of code:
WebRowSet recipient = new WebRowSetImpl(); java.io.FileReader reader = new java.io.FileReader("priceList.xml"); recipient.readXml(reader);
RowSet
objects are more than just the data they contain.
They have properties and metadata about their columns as
well. Therefore, an XML document representing a WebRowSet
object includes this other information in addition to its
data. Further, the data in an XML document includes both
current values and original values. (Recall that original values are the values
that existed immediately before the most recent changes to
data were made. These values are necessary for checking
if the corresponding value in the database has been
changed, thus creating a conflict over which value should
be persistent: the new value you put in the RowSet
object or
the new value someone else put in the database.)
The WebRowSet XML Schema, itself an XML document, defines
what an XML document representing a WebRowSet
object will
contain and also the format in which it must be presented.
Both the sender and the recipient use this schema because
it tells the sender how to write the XML document (which represents the WebRowSet
object) and the recipient
how to parse the XML document. Because the actual writing and
reading is done internally by the implementations of the
methods writeXML
and readXml
, you, as a user, do not need
to understand what is in the WebRowSet XML Schema
document.
XML documents contain elements and subelements in a
hierarchical structure. The following are the three main
elements in an XML document describing a WebRowSet
object:
Element tags signal the beginning and end of an element.
For example, the <properties>
tag signals the beginning of
the properties element, and the </properties>
tag signals its
end. The <map/>
tag is a shorthand way of saying that the map
subelement (one of the subelements in the properties
element) has not been assigned a value. The following sample XML documents uses spacing and indentation to make it easier
to read, but those are not used in an actual XML document,
where spacing does not mean anything.
The next three sections show you what the three main
elements contain for the WebRowSet
priceList
object,
created in the sample WebRowSetSample.java
.
Calling the method writeXML
on the priceList
object would
produce an XML document describing priceList
. The
properties section of this XML document would look like the
following:
<properties> <command>select COF_NAME, PRICE from COFFEES</command> <concurrency>1008</concurrency> <datasource><null/></datasource> <escape-processing>true</escape-processing> <fetch-direction>1000</fetch-direction> <fetch-size>0</fetch-size> <isolation-level>2</isolation-level> <key-columns> <column>1</column> </key-columns> <map> </map> <max-field-size>0</max-field-size> <max-rows>0</max-rows> <query-timeout>0</query-timeout> <read-only>true</read-only> <rowset-type>ResultSet.TYPE_SCROLL_INSENSITIVE</rowset-type> <show-deleted>false</show-deleted> <table-name>COFFEES</table-name> <url>jdbc:mysql://localhost:3306/testdb</url> <sync-provider> <sync-provider-name>com.sun.rowset.providers.RIOptimisticProvider</sync-provider-name> <sync-provider-vendor>Sun Microsystems Inc.</sync-provider-vendor> <sync-provider-version>1.0</sync-provider-version> <sync-provider-grade>2</sync-provider-grade> <data-source-lock>1</data-source-lock> </sync-provider> </properties>
Notice that some properties have no value. For
example, the datasource
property is indicated with
the <datasource/>
tag, which is a shorthand way of saying
<datasource></datasource>
. No value is given
because the url
property is set. Any connections that are
established will be done using this JDBC URL, so no
DataSource
object needs to be set. Also, the username
and
password
properties are not listed because they must
remain secret.
The metadata section of the XML document describing a
WebRowSet
object contains information about the columns in
that WebRowSet
object. The following shows what this
section looks like for the WebRowSet
object
priceList
. Because the priceList
object has two columns,
the XML document describing it has two
<column-definition>
elements. Each
<column-definition>
element has subelements giving
information about the column being described.
<metadata> <column-count>2</column-count> <column-definition> <column-index>1</column-index> <auto-increment>false</auto-increment> <case-sensitive>false</case-sensitive> <currency>false</currency> <nullable>0</nullable> <signed>false</signed> <searchable>true</searchable> <column-display-size>32</column-display-size> <column-label>COF_NAME</column-label> <column-name>COF_NAME</column-name> <schema-name></schema-name> <column-precision>32</column-precision> <column-scale>0</column-scale> <table-name>coffees</table-name> <catalog-name>testdb</catalog-name> <column-type>12</column-type> <column-type-name>VARCHAR</column-type-name> </column-definition> <column-definition> <column-index>2</column-index> <auto-increment>false</auto-increment> <case-sensitive>true</case-sensitive> <currency>false</currency> <nullable>0</nullable> <signed>true</signed> <searchable>true</searchable> <column-display-size>12</column-display-size> <column-label>PRICE</column-label> <column-name>PRICE</column-name> <schema-name></schema-name> <column-precision>10</column-precision> <column-scale>2</column-scale> <table-name>coffees</table-name> <catalog-name>testdb</catalog-name> <column-type>3</column-type> <column-type-name>DECIMAL</column-type-name> </column-definition> </metadata>
From this metadata section, you can see that there are two
columns in each row. The first column is COF_NAME
, which
holds values of type VARCHAR
. The second column is PRICE
,
which holds values of type REAL
, and so on. Note that the
column types are the data types used in the data source,
not types in the Java programming language. To get or
update values in the COF_NAME
column, you use the methods getString
or
updateString
, and the driver makes the conversion to
the VARCHAR
type, as it usually does.
The data section gives the values for each column in each
row of a WebRowSet
object. If you have populated
the priceList
object and not made any changes to it, the data
element of the XML document will look like the following.
In the next section you will see how the XML document
changes when you modify the data in the priceList
object.
For each row there is a <currentRow>
element, and
because priceList
has two columns, each
<currentRow>
element contains two <columnValue>
elements.
<data> <currentRow> <columnValue>Colombian</columnValue> <columnValue>7.99</columnValue> </currentRow> <currentRow> <columnValue>Colombian_Decaf</columnValue> <columnValue>8.99</columnValue> </currentRow> <currentRow> <columnValue>Espresso</columnValue> <columnValue>9.99</columnValue> </currentRow> <currentRow> <columnValue>French_Roast</columnValue> <columnValue>8.99</columnValue> </currentRow> <currentRow> <columnValue>French_Roast_Decaf</columnValue> <columnValue>9.99</columnValue> </currentRow> </data>
You make changes to a WebRowSet
object the same way you do
to a CachedRowSet
object. Unlike a CachedRowSet
object,
however, a WebRowSet
object keeps track of updates,
insertions, and deletions so that the writeXML
method can
write both the current values and the original values. The
three sections that follow demonstrate making changes to
the data and show what the XML document describing the
WebRowSet
object looks like after each change. You do not
have to do anything at all regarding the XML document; any
change to it is made automatically, just
as with writing and reading the XML document.
If the owner of the Coffee Break chain wants to add a new coffee to the price list, the code might look like this:
priceList.absolute(3); priceList.moveToInsertRow(); priceList.updateString(COF_NAME, "Kona"); priceList.updateFloat(PRICE, 8.99f); priceList.insertRow(); priceList.moveToCurrentRow();
In the reference implementation, an insertion is made
immediately following the current row. In the preceding
code fragment, the current row is the third row, so the new
row would be added after the third row and become the new
fourth row. To reflect this insertion, the XML document
would have the following <insertRow>
element added to
it after the third <currentRow>
element in the
<data>
element.
The <insertRow>
element will look similar to the
following.
<insertRow> <columnValue>Kona</columnValue> <columnValue>8.99</columnValue> </insertRow>
The owner decides that Espresso is not selling enough and
should be removed from the coffees sold at The Coffee
Break shops. The owner therefore wants to delete Espresso from the price
list. Espresso is in the third row of the priceList
object, so
the following lines of code delete it:
priceList.absolute(3); priceList.deleteRow();
The following <deleteRow>
element will appear after
the second row in the data section of the XML document,
indicating that the third row has been deleted.
<deleteRow> <columnValue>Espresso</columnValue> <columnValue>9.99</columnValue> </deleteRow>
The owner further decides that the price of Colombian coffee is too expensive and wants to lower it to .99 a pound. The following code sets the new price for Colombian coffee, which is in the first row, to .99 a pound:
priceList.first(); priceList.updateFloat(PRICE, 6.99);
The XML document will reflect this change in an
<updateRow>
element that gives the new value. The value for
the first column did not change, so there is an
<updateValue>
element only for the second column:
<currentRow> <columnValue>Colombian</columnValue> <columnValue>7.99</columnValue> <updateRow>6.99</updateRow> </currentRow>
At this point, with the insertion of a row, the deletion of
a row, and the modification of a row, the XML document for
the priceList
object would look like the following:
<data> <insertRow> <columnValue>Kona</columnValue> <columnValue>8.99</columnValue> </insertRow> <currentRow> <columnValue>Colombian</columnValue> <columnValue>7.99</columnValue> <updateRow>6.99</updateRow> </currentRow> <currentRow> <columnValue>Colombian_Decaf</columnValue> <columnValue>8.99</columnValue> </currentRow> <deleteRow> <columnValue>Espresso</columnValue> <columnValue>9.99</columnValue> </deleteRow> <currentRow> <columnValue>French_Roast</columnValue> <columnValue>8.99</columnValue> </currentRow> <currentRow> <columnValue>French_Roast_Decaf</columnValue> <columnValue>9.99</columnValue> </currentRow> </data>
The sample WebRowSetSample.java
demonstrates all the features described on this page.