WebRowSetDataProvider.java
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:35k
源码类别:

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: WebRowSetDataProvider.java,v 1.4 2005/10/15 11:43:20 pdoubleya Exp $
  3.  *
  4.  * Created on March 21, 2005, 9:52 AM
  5.  * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle,
  6.  * Santa Clara, California 95054, U.S.A. All rights reserved.
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Lesser General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2.1 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Lesser General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Lesser General Public
  19.  * License along with this library; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  21.  */
  22. package org.jdesktop.dataset.provider.sql;
  23. import java.io.InputStream;
  24. import java.io.InputStreamReader;
  25. import java.io.Reader;
  26. import java.math.BigDecimal;
  27. import java.math.BigInteger;
  28. import java.net.URL;
  29. import java.sql.SQLException;
  30. import java.sql.Timestamp;
  31. import java.sql.Types;
  32. import java.util.HashMap;
  33. import java.util.LinkedList;
  34. import java.util.List;
  35. import java.util.Map;
  36. import java.util.Stack;
  37. import javax.sql.RowSetMetaData;
  38. import javax.sql.rowset.RowSetMetaDataImpl;
  39. import javax.swing.SwingUtilities;
  40. import javax.xml.parsers.SAXParser;
  41. import javax.xml.parsers.SAXParserFactory;
  42. import org.jdesktop.dataset.DataColumn;
  43. import org.jdesktop.dataset.DataProvider;
  44. import org.jdesktop.dataset.DataRow;
  45. import org.jdesktop.dataset.DataTable;
  46. import org.jdesktop.dataset.event.TableChangeEvent;
  47. import org.jdesktop.dataset.provider.LoadTask;
  48. import org.jdesktop.dataset.provider.SaveTask;
  49. import org.jdesktop.dataset.provider.LoadTask.LoadItem;
  50. import org.xml.sax.Attributes;
  51. import org.xml.sax.InputSource;
  52. import org.xml.sax.SAXException;
  53. import org.xml.sax.XMLReader;
  54. import org.xml.sax.ext.LexicalHandler;
  55. import org.xml.sax.helpers.DefaultHandler;
  56. import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
  57. /**
  58.  * Takes webrowset XML and uses it to populate a DataTable. This particular
  59.  * DataProvider will drop all of the columns from the DataTable and add new
  60.  * columns back in based on the meta data in the XML.
  61.  *
  62.  * @author Richard Bair
  63.  */
  64. public class WebRowSetDataProvider extends DataProvider {
  65.     /**
  66.      * A static instance of the Factory used to parse documents in this WebRowSet implementation
  67.      */
  68.     private static final SAXParserFactory FACTORY = SAXParserFactory.newInstance();
  69.     
  70.     private URL url;
  71.     
  72.     private Runnable completionRunnable;
  73.     private Runnable metadataCompleteRunnable;
  74.     
  75.     /**
  76.      * Static initialization code for the FACTORY. Currently setting validating to false.
  77.      */
  78.     static {
  79.         FACTORY.setValidating(false);
  80.     }
  81.     
  82.     /** Creates a new instance of WebRowSetDataProvider */
  83.     public WebRowSetDataProvider() {
  84.     }
  85.     
  86.     protected SaveTask createSaveTask(DataTable[] tables) {
  87.         return new SaveTask(tables) {
  88.             protected void saveData(DataTable[] tables) throws Exception {}
  89.         };
  90.     }
  91.     
  92.     final class RowLoadItem {
  93.         public Object[] values;
  94.         public DataRow.DataRowStatus status;
  95.     }
  96.     
  97.     
  98.     protected LoadTask createLoadTask(DataTable[] tables) {
  99.         return new LoadTask(tables) {
  100.             
  101.             class WebRowSetXMLHandler extends DefaultHandler implements LexicalHandler {
  102.                 
  103.                 DataTable table;
  104.                 /**
  105.                  * List to keep track of rows that need to be loaded
  106.                  */
  107.                 private List dataToLoad = new LinkedList();
  108.                 /**
  109.                  * Stack to keep track of which tags have been seen
  110.                  */
  111.                 private Stack<String> tagStack = new Stack<String>();
  112.                 /**
  113.                  * Set to true if we have seen an opening "properties" tag, but not a closing.
  114.                  * inProperties, inMetaData, and inData are mutually exclusive
  115.                  */
  116.                 private boolean inProperties = false;
  117.                 /**
  118.                  * Set to true if we have seen an opening "metadata" tag, but not a closing.
  119.                  * inProperties, inMetaData, and inData are mutually exclusive
  120.                  */
  121.                 private boolean inMetaData = false;
  122.                 /**
  123.                  * Set to true if we have seen an opening "data" tag, but not a closing.
  124.                  * inProperties, inMetaData, and inData are mutually exclusive
  125.                  */
  126.                 private boolean inData = false;
  127.                 /**
  128.                  * The meta data object being updated. This metaData object is modified until the
  129.                  * closing "metadata" tag is found. Then the ShopLogicWebRowSet's meta data is updated
  130.                  * in one fell stroke
  131.                  */
  132.                 private RowSetMetaData metaData = null;
  133.                 /**
  134.                  * Keeps track of which column we are currently dealing with. This is used both by the
  135.                  * metadata parsing code, and the data parsing code
  136.                  */
  137.                 private int columnIndex = 1;
  138.                 /**
  139.                  * This is a stack of keyColumns parsed. After being parsed and added to this stack, they are
  140.                  * added to an int[] and set in the WebRowSet.
  141.                  */
  142.                 private Stack<Integer> keyColumnsStack = new Stack<Integer>();
  143.                 /**
  144.                  * Keeps track of the "type" value while parsing the type map.
  145.                  */
  146.                 private String mapType;
  147.                 /**
  148.                  * Keeps track of the "class" value while parsing the type map.
  149.                  */
  150.                 private String mapClass;
  151.                 /**
  152.                  * This is the map of types, as parsed from the file. After the closing "map" tag is found, the
  153.                  * WebRowSet is updated.
  154.                  */
  155.                 private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>();
  156.                 /**
  157.                  * Contains the data value parsed from the <code>characters</code> method. This is simply a string.
  158.                  * The <code>setValue</code> method is responsible for parsing this into an int, bool, etc.
  159.                  */
  160.                 private String data;
  161.                 /**
  162.                  * Keeps track of whether the last tag read was null.
  163.                  */
  164.                 private boolean wasNull;
  165.                 /**
  166.                  * This String is used while in the data portion of parsing. It is used as the first part of they
  167.                  * key in the cache for a row.
  168.                  */
  169.                 private String tableName = "";
  170.                 /**
  171.                  * This list maintains the rowValues as parsed from the file. After they are all parsed,
  172.                  * they are passed to the row.
  173.                  */
  174.                 private Object[] rowValues;
  175.                 /**
  176.                  * The index of the current row being processed. This is 1 based
  177.                  */
  178.                 private int currentRow = 0;
  179.                 
  180.                 
  181.                 public WebRowSetXMLHandler(DataTable table) {
  182.                     this.table = table;
  183.                 }
  184.                 
  185.                 public void comment(char[] ch, int start, int length)
  186.                 throws SAXException {
  187.                     
  188.                 }
  189.                 
  190.                 public void startCDATA()
  191.                 throws SAXException {
  192.                 }
  193.                 
  194.                 public void endCDATA()  throws SAXException {
  195.                 }
  196.                 
  197.                 public void startEntity(String name)
  198.                 throws SAXException {
  199.                 }
  200.                 
  201.                 public void endEntity(String name)
  202.                 throws SAXException {
  203.                 }
  204.                 
  205.                 public void startDTD(
  206.                         String name, String publicId, String systemId)
  207.                         throws SAXException {
  208.                 }
  209.                 
  210.                 public void endDTD()
  211.                 throws SAXException {
  212.                 }
  213.                 
  214.                 /**
  215.                  * Updates the <code>data</code> variable with the given characters using the default character set
  216.                  * @inheritDoc
  217.                  */
  218.                 public void characters(char[] ch, int start, int length) throws SAXException {
  219.                     //Remember that characters may be called multiple times for the same
  220.                     //element, so if data is null then the characters delivered here are
  221.                     //the data, otherwise append the characters to data
  222.                     if (data == null) {
  223.                         data = new String(ch, start, length);
  224.                     } else {
  225.                         data = data + new String(ch, start, length);
  226.                     }
  227.                     data = data.trim();
  228.                 }
  229.                 
  230.                 /**
  231.                  * Helper method that updates the current row at the given column with the given value.
  232.                  * This code actually determines the column type for the designated column, and uses that
  233.                  * information to transform the value into the proper data type. Data MAY be null
  234.                  * @param columnIndex
  235.                  * @param value
  236.                  * @throws Exception
  237.                  */
  238.                 private void setValue(int columnIndex, String value) throws Exception {
  239.                     //TODO Take into account the possiblity of a collision, and notify listeners if necessary
  240.                     if (wasNull || value == null) {
  241.                         rowValues[columnIndex - 1] = null;
  242.                     } else {
  243.                         switch (metaData.getColumnType(columnIndex)) {
  244.                             case Types.TINYINT:
  245.                                 rowValues[columnIndex - 1] = Byte.valueOf(value.trim());
  246.                                 break;
  247.                             case Types.SMALLINT:
  248.                                 rowValues[columnIndex - 1] = Short.valueOf(value.trim());
  249.                                 break;
  250.                             case Types.INTEGER:
  251.                                 rowValues[columnIndex - 1] = Integer.valueOf(value.trim());
  252.                                 break;
  253.                             case Types.BIGINT:
  254.                                 rowValues[columnIndex - 1] = Long.valueOf(value.trim());
  255.                                 break;
  256.                             case Types.REAL:
  257.                                 rowValues[columnIndex - 1] = Float.valueOf(value.trim());
  258.                                 break;
  259.                             case Types.FLOAT:
  260.                             case Types.DOUBLE:
  261.                                 rowValues[columnIndex - 1] = Double.valueOf(value.trim());
  262.                                 break;
  263.                             case Types.DECIMAL:
  264.                             case Types.NUMERIC:
  265.                                 rowValues[columnIndex - 1] = new BigDecimal(value.trim());
  266.                                 break;
  267.                             case Types.BOOLEAN:
  268.                             case Types.BIT:
  269.                                 rowValues[columnIndex - 1] = Boolean.valueOf(value.trim());
  270.                                 break;
  271.                             case Types.CHAR:
  272.                             case Types.VARCHAR:
  273.                             case Types.LONGVARCHAR:
  274.                                 rowValues[columnIndex - 1] = value;
  275.                                 break;
  276.                             case Types.VARBINARY:
  277.                             case Types.LONGVARBINARY:
  278.                             case Types.BINARY:
  279.                                 byte[] bytes = Base64.decode(value);
  280.                                 rowValues[columnIndex - 1] = bytes;
  281.                                 break;
  282.                             case Types.DATE:
  283.                             case Types.TIME:
  284.                             case Types.TIMESTAMP:
  285.                                 rowValues[columnIndex - 1] = new Timestamp(Long.parseLong(value.trim()));
  286.                                 break;
  287.                             case Types.ARRAY:
  288.                             case Types.BLOB:
  289.                             case Types.CLOB:
  290.                             case Types.DATALINK:
  291.                             case Types.DISTINCT:
  292.                             case Types.JAVA_OBJECT:
  293.                             case Types.OTHER:
  294.                             case Types.REF:
  295.                             case Types.STRUCT:
  296.                                 //what to do with this?
  297.                                 break;
  298.                             default :
  299.                                 //do nothing
  300.                         }
  301.                     }
  302.                 }
  303.                 
  304.                 /**
  305.                  * @inheritDoc
  306.                  */
  307.                 public void endDocument() throws SAXException {
  308.                     doLoad(table, dataToLoad);
  309.                     if (completionRunnable != null) {
  310.                         SwingUtilities.invokeLater(completionRunnable);
  311.                     }
  312.                 }
  313.                 
  314.                 /**
  315.                  * @inheritDoc
  316.                  */
  317.                 public void endElement(String uri, String localName, String qName) throws SAXException {
  318.                     if (tagStack.size() == 0) {
  319.                         return;
  320.                     }
  321.                     //get the last tag seen
  322.                     String tag = tagStack.pop();
  323.                     //handle each tag. Handle the data tags first since those will be called most frequently
  324.                     try {
  325.                         if (tag.equals("null")) {
  326.                             wasNull = true;
  327.                         } else if (tag.equals("columnvalue")) {
  328.                             //set the current column value
  329.                             setValue(columnIndex++, wasNull ? null : data);
  330.                         } else if (tag.equals("updatevalue")) {
  331.                             //set the update column value (the column to
  332.                             //apply the update to is the previous
  333.                             //columnIndex)
  334.                             setValue(columnIndex-1, wasNull ? null : data);
  335.                         } else if (tag.equals("currentrow")) {
  336.                             RowLoadItem loadItem = new RowLoadItem();
  337.                             loadItem.values = new Object[rowValues.length];
  338.                             System.arraycopy(rowValues, 0, loadItem.values, 0, rowValues.length);
  339.                             loadItem.status = DataRow.DataRowStatus.UNCHANGED;
  340.                             dataToLoad.add(loadItem);
  341.                         } else if (tag.equals("insertrow")) {
  342.                             RowLoadItem loadItem = new RowLoadItem();
  343.                             loadItem.values = new Object[rowValues.length];
  344.                             System.arraycopy(rowValues, 0, loadItem.values, 0, rowValues.length);
  345.                             loadItem.status = DataRow.DataRowStatus.INSERTED;
  346.                         } else if (tag.equals("deleterow")) {
  347.                             RowLoadItem loadItem = new RowLoadItem();
  348.                             loadItem.values = new Object[rowValues.length];
  349.                             System.arraycopy(rowValues, 0, loadItem.values, 0, rowValues.length);
  350.                             loadItem.status = DataRow.DataRowStatus.DELETED;
  351.                         } else if (tag.equals("modifyrow")) {
  352.                             RowLoadItem loadItem = new RowLoadItem();
  353.                             loadItem.values = new Object[rowValues.length];
  354.                             System.arraycopy(rowValues, 0, loadItem.values, 0, rowValues.length);
  355.                             loadItem.status = DataRow.DataRowStatus.UPDATED;
  356.                         }  else if (tag.equals("column")) {
  357.                             //in key-columns
  358.                             if (!wasNull) {
  359.                                 keyColumnsStack.push(new Integer(data.trim()));
  360.                             }
  361.                         } else if (tag.equals("type")) {
  362.                             mapType = wasNull ? null : data;
  363.                         } else if (tag.equals("class")) {
  364.                             mapClass = wasNull ? null : data;
  365.                             //add the type and class to the typeMap
  366.                             typeMap.put(mapType, mapClass == null ? null : Class.forName(mapClass));
  367.                         } else if (tag.equals("table-name")) {
  368.                             if (inProperties) {
  369. //                                        setTableName(wasNull ? null : data);
  370.                             } else if (inMetaData) {
  371.                                 metaData.setTableName(columnIndex, wasNull ? null : data);
  372.                             }
  373.                         } else if (tag.equals("column-count")) {
  374.                             metaData.setColumnCount(wasNull ? 0 : Integer.parseInt(data.trim()));
  375.                         } else if (tag.equals("column-index")) {
  376.                             columnIndex = Integer.parseInt(data.trim());
  377.                         } else if (tag.equals("key-columns")) {
  378.                             int[] kc = new int[keyColumnsStack.size()];
  379.                             int i = 0;
  380.                             for (Integer col : keyColumnsStack) {
  381.                                 kc[i++] = col.intValue();
  382.                             }
  383.                             try {
  384. //                                        setKeyColumns(kc);
  385.                             } catch (Exception e) {
  386.                                 e.printStackTrace();
  387. //                                        LOG.error("Failed to set the key columns, even after parsing. Columns were " + keyColumnsStack, e);
  388.                             }
  389.                         } else if (tag.equals("map")) {
  390.                             //if the tag was a map tag, then put the map
  391.                             // elements into the map
  392. //                                    setTypeMap(typeMap);
  393.                         } else if (tag.equals("auto-increment")) {
  394.                             metaData.setAutoIncrement(columnIndex, wasNull ? false : Boolean.parseBoolean(data));
  395.                         } else if (tag.equals("case-sensitive")) {
  396.                             metaData.setCaseSensitive(columnIndex, wasNull ? false : Boolean.parseBoolean(data));
  397.                         } else if (tag.equals("currency")) {
  398.                             metaData.setCurrency(columnIndex, wasNull ? false : Boolean.parseBoolean(data.trim()));
  399.                         } else if (tag.equals("nullable")) {
  400.                             metaData.setNullable(columnIndex, wasNull ? 0 : Integer.parseInt(data.trim()));
  401.                         } else if (tag.equals("signed")) {
  402.                             metaData.setSigned(columnIndex, wasNull ? false : Boolean.parseBoolean(data.trim()));
  403.                         } else if (tag.equals("searchable")) {
  404.                             metaData.setSearchable(columnIndex, wasNull ? false : Boolean.parseBoolean(data.trim()));
  405.                         } else if (tag.equals("column-display-size")) {
  406.                             metaData.setColumnDisplaySize(columnIndex, wasNull ? 255 : Integer.parseInt(data.trim()));
  407.                         } else if (tag.equals("column-label")) {
  408.                             metaData.setColumnLabel(columnIndex, wasNull ? null : data);
  409.                         } else if (tag.equals("column-name")) {
  410.                             metaData.setColumnName(columnIndex, data);
  411.                         } else if (tag.equals("schema-name")) {
  412.                             metaData.setSchemaName(columnIndex, wasNull ? null : data);
  413.                         } else if (tag.equals("column-precision")) {
  414.                             metaData.setPrecision(columnIndex, wasNull ? 0 : Integer.parseInt(data.trim()));
  415.                         } else if (tag.equals("column-scale")) {
  416.                             metaData.setScale(columnIndex, wasNull ? 0 : Integer.parseInt(data.trim()));
  417.                         } else if (tag.equals("catalog-name")) {
  418.                             metaData.setCatalogName(columnIndex, wasNull ? null : data);
  419.                         } else if (tag.equals("column-type")) {
  420.                             metaData.setColumnType(columnIndex, wasNull ? Types.VARCHAR : Integer.parseInt(data.trim()));
  421.                         } else if (tag.equals("column-type-name")) {
  422.                             metaData.setColumnTypeName(columnIndex, wasNull ? null : data);
  423.                         } else if (tag.equals("metadata")) {
  424.                             //drop all of the columns in the data table
  425.                             //and rebuild them based on this meta-data
  426.                             SwingUtilities.invokeAndWait(new Runnable() {
  427.                                 public void run() {
  428.                                     table.clear();
  429.                                     DataColumn[] cols = table.getColumns().toArray(new DataColumn[table.getColumns().size()]);
  430.                                     for (DataColumn col : cols) {
  431.                                         table.dropColumn(col.getName());
  432.                                     }
  433.                                     
  434.                                     //time to rebuild
  435.                                     try {
  436.                                         for (int i=0; i<metaData.getColumnCount(); i++) {
  437.                                             DataColumn col = table.createColumn(metaData.getColumnName(i+1));
  438.                                             switch (metaData.getColumnType(i+1)) {
  439.                                                 case Types.TINYINT:
  440.                                                     col.setType(Byte.class);
  441.                                                     break;
  442.                                                 case Types.SMALLINT:
  443.                                                     col.setType(Short.class);
  444.                                                     break;
  445.                                                 case Types.INTEGER:
  446.                                                     col.setType(Integer.class);
  447.                                                     break;
  448.                                                 case Types.BIGINT:
  449.                                                     col.setType(BigInteger.class);
  450.                                                     break;
  451.                                                 case Types.REAL:
  452.                                                     col.setType(Float.class);
  453.                                                     break;
  454.                                                 case Types.FLOAT:
  455.                                                 case Types.DOUBLE:
  456.                                                     col.setType(Double.class);
  457.                                                     break;
  458.                                                 case Types.DECIMAL:
  459.                                                 case Types.NUMERIC:
  460.                                                     col.setType(BigDecimal.class);
  461.                                                     break;
  462.                                                 case Types.BOOLEAN:
  463.                                                 case Types.BIT:
  464.                                                     col.setType(Boolean.class);
  465.                                                     break;
  466.                                                 case Types.CHAR:
  467.                                                 case Types.VARCHAR:
  468.                                                 case Types.LONGVARCHAR:
  469.                                                     col.setType(String.class);
  470.                                                     break;
  471.                                                 case Types.VARBINARY:
  472.                                                 case Types.LONGVARBINARY:
  473.                                                 case Types.BINARY:
  474.                                                     col.setType(Byte[].class);
  475.                                                     break;
  476.                                                 case Types.DATE:
  477.                                                 case Types.TIME:
  478.                                                 case Types.TIMESTAMP:
  479.                                                     col.setType(Timestamp.class);
  480.                                                     break;
  481.                                                 case Types.ARRAY:
  482.                                                 case Types.BLOB:
  483.                                                 case Types.CLOB:
  484.                                                 case Types.DATALINK:
  485.                                                 case Types.DISTINCT:
  486.                                                 case Types.JAVA_OBJECT:
  487.                                                 case Types.OTHER:
  488.                                                 case Types.REF:
  489.                                                 case Types.STRUCT:
  490.                                                     //what to do with this?
  491.                                                     break;
  492.                                                 default :
  493.                                                     //do nothing
  494.                                             }
  495.                                         }
  496.                                     } catch (Exception e) {
  497.                                         e.printStackTrace();
  498.                                     }
  499.                                     // TODO: new API
  500.                                     // table.fireDataTableChanged(new TableChangeEvent(table));
  501.                                     
  502.                                 }
  503.                             });
  504.                             if (metadataCompleteRunnable != null) {
  505.                                 SwingUtilities.invokeLater(metadataCompleteRunnable);
  506.                             }
  507.                         }
  508.                     } catch (Exception e) {
  509.                         e.printStackTrace();
  510. //                                LOG.error("Failed to parse something", e);
  511.                     }
  512.                     data = null;
  513.                     if (dataToLoad.size() >= 100) {
  514.                         doLoad(table, dataToLoad);
  515.                         dataToLoad = new LinkedList<RowLoadItem>();
  516.                     }
  517.                 }
  518.                 
  519.                 /**
  520.                  * @inheritDoc
  521.                  */
  522.                 public void startDocument() throws SAXException {
  523. //                            LOG.debug("Start of Document");
  524.                 }
  525.                 
  526.                 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
  527.                     //reset the wasNull flag
  528.                     wasNull = false;
  529.                     //push the element name onto the stack. In this way, when
  530.                     // the characters method is called, I know what kind of data
  531.                     //I'm dealing with.
  532.                     String tag = qName.toLowerCase();
  533.                     tagStack.push(tag);
  534.                     try {
  535.                         if (tag.equals("properties")) {
  536.                             inProperties = true;
  537.                             inMetaData = false;
  538.                             inData = false;
  539.                         } else if (tag.equals("metadata")) {
  540.                             inProperties = false;
  541.                             inMetaData = true;
  542.                             inData = false;
  543.                             metaData = new RowSetMetaDataImpl();
  544.                         } else if (tag.equals("data")) {
  545.                             inProperties = false;
  546.                             inMetaData = false;
  547.                             inData = true;
  548.                             //construct the rowValues array
  549.                             rowValues = new Object[metaData.getColumnCount()];
  550.                         } else if (tag.equals("currentrow")) {
  551.                             columnIndex = 1;
  552.                             reinitRowValues();
  553.                             currentRow++;
  554.                         } else if (tag.equals("insertrow")) {
  555.                             columnIndex = 1;
  556.                             reinitRowValues();
  557.                             currentRow++;
  558.                         } else if (tag.equals("deleterow")) {
  559.                             columnIndex = 1;
  560.                             reinitRowValues();
  561.                             currentRow++;
  562.                         } else if (tag.equals("modifyrow")) {
  563.                             columnIndex = 1;
  564.                             reinitRowValues();
  565.                             currentRow++;
  566.                         }
  567.                     } catch (Exception e) {
  568.                         e.printStackTrace();
  569.                     }
  570.                 }
  571.                 
  572.                 /**
  573.                  * Utility method that clears out the rowValues array
  574.                  */
  575.                 private void reinitRowValues() {
  576.                     for (int i=0; i<rowValues.length; i++) {
  577.                         rowValues[i] = null;
  578.                     }
  579.                 }
  580.             }
  581.             
  582.             protected void loadData(LoadTask.LoadItem[] items) {
  583.                 for (LoadItem item : items) {
  584.                     DataTable table = item.table;
  585.                     List<RowLoadItem> loadItems = (List<RowLoadItem>)item.data;
  586.                     for (RowLoadItem loadItem : loadItems) {
  587.                         
  588.                         DataRow row = table.appendRowNoEvent();
  589.                         List<DataColumn> cols = table.getColumns();
  590.                         for (int i=0; i<loadItem.values.length; i++) {
  591.                             try {
  592.                                 row.setValue(cols.get(i).getName(), loadItem.values[i]);
  593.                             } catch (Exception e) {
  594.                                 System.out.println(loadItem.values.length);
  595.                             }
  596.                         }
  597.                         row.setStatus(loadItem.status);
  598.                         item.table.fireDataTableChanged(TableChangeEvent.newRowAddedEvent(item.table, row));
  599.                     }
  600.                     item.table.fireDataTableChanged(TableChangeEvent.newLoadCompleteEvent(item.table));
  601.                 }
  602.             }
  603.             
  604.             protected void readData(DataTable[] tables) throws Exception {
  605.                 //get the XML from the url
  606.                 try {
  607.                     for (int i=0; i<tables.length; i++) {
  608.                         InputStream is = url.openStream();
  609.                         readXml(new InputStreamReader(is), tables[i]);
  610.                     }
  611.                 } catch (Exception e) {
  612.                     e.printStackTrace();
  613.                 }
  614.             }
  615.             
  616.             public void doLoad(DataTable table, List items) {
  617.                 super.scheduleLoad(new LoadTask.LoadItem(table, items));
  618.             }
  619.             
  620.             /**
  621.              * Originally this method was implemented with a PullParser. However, the
  622.              * PullParser did not have very good error messages, so debugging the XML
  623.              * was murder. A normal SAX parser is being used at this time.
  624.              *
  625.              * @inheritDoc
  626.              */
  627.             public void readXml(Reader reader, final DataTable table) throws SQLException {
  628.                 try {
  629.                     /*
  630.                      * Parsing is done via SAX. The basic methodology is to keep a stack of tags seen.
  631.                      * Also, a flag is kept to keep track of whether or not a <null/> tag has been seen.
  632.                      * This flag is reset to false whenever a new tag is started, but is set to true when
  633.                      * the end of the <null> tag is found.
  634.                      * Also, A single variable contains the results of the character data for the current tag.
  635.                      * This variable is read after the end tag is found. You will find that all work is
  636.                      * done after the entire element has been read (after the end tag).
  637.                      */
  638.                     
  639.                     WebRowSetXMLHandler handler = new WebRowSetXMLHandler(table);
  640.                     SAXParser parser = FACTORY.newSAXParser();
  641.                     XMLReader xmlReader = parser.getXMLReader();
  642.                     xmlReader.setProperty(
  643.                             "http://xml.org/sax/properties/lexical-handler",
  644.                             handler
  645.                             );
  646.                     
  647.                     parser.parse(new InputSource(reader), handler );
  648.                 } catch (Exception e) {
  649.                     e.printStackTrace();
  650.                     throw new SQLException("Error while parsing a the xml document for a WebRowSetDataProvider");
  651.                 }
  652.             }
  653.         };
  654.         
  655.         
  656.     }
  657. /*
  658.     public static void main(String... args) {
  659.         DataSet ds = new DataSet();
  660.         DataTable dt = ds.createTable();
  661.         dt.setName("Rowset");
  662.         DataProvider dp = new WebRowSetDataProvider();
  663.         dt.setDataProvider(dp);
  664.         JFrame frame = new JFrame();
  665.     //   JTable table = new JTable();
  666.  //
  667.         //Binding b = BindingFactory.bind(table, dt);
  668.  
  669.         TabularDataModelAdapter adapter = new TabularDataModelAdapter(dt);
  670.  
  671.  
  672.      //   JNTable table = new JNTable();
  673.    //     new DirectTableBinding(table.getTable(),adapter);
  674.  
  675.         frame.getContentPane().setLayout(new BorderLayout());
  676.         frame.getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);
  677.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  678.         frame.setSize(800,600);
  679.         frame.setVisible(true);
  680.         dt.load();
  681. //        dt.loadAndWait();
  682. //        System.out.println(dt.getRows().size());
  683. //        List<DataColumn> cols = dt.getColumns();
  684. //        for (DataColumn col : cols) {
  685. //            System.out.println(col.getName());
  686. //        }
  687.     }
  688.  
  689.  */
  690.     
  691.     public URL getUrl() {
  692.         return url;
  693.     }
  694.     
  695.     public void setUrl(URL url) {
  696.         this.url = url;
  697.     }
  698.     
  699.     public Runnable getCompletionRunnable() {
  700.         return completionRunnable;
  701.     }
  702.     
  703.     public void setCompletionRunnable(Runnable completionRunnable) {
  704.         this.completionRunnable = completionRunnable;
  705.     }
  706.     
  707.     public Runnable getMetadataCompleteRunnable() {
  708.         return metadataCompleteRunnable;
  709.     }
  710.     
  711.     public void setMetadataCompleteRunnable(Runnable metadataCompleteRunnable) {
  712.         this.metadataCompleteRunnable = metadataCompleteRunnable;
  713.     }
  714.     
  715.     
  716.     
  717. }