1 /*
   2  * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.rowset.internal;
  27 
  28 import java.util.*;
  29 
  30 import org.xml.sax.*;
  31 import org.xml.sax.helpers.*;
  32 
  33 import java.sql.*;
  34 import javax.sql.*;
  35 
  36 import javax.sql.rowset.*;
  37 import com.sun.rowset.*;
  38 import java.io.IOException;
  39 import java.text.MessageFormat;
  40 
  41 /**
  42  * The document handler that receives parse events that an XML parser sends while it
  43  * is parsing an XML document representing a <code>WebRowSet</code> object. The
  44  * parser sends strings to this <code>XmlReaderContentHandler</code> and then uses
  45  * these strings as arguments for the <code>XmlReaderContentHandler</code> methods
  46  * it invokes. The final goal of the SAX parser working with an
  47  * <code>XmlReaderContentHandler</code> object is to read an XML document that represents
  48  * a <code>RowSet</code> object.
  49  * <P>
  50  * A rowset consists of its properties, metadata, and data values. An XML document
  51  * representating a rowset includes the values in these three categories along with
  52  * appropriate XML tags to identify them.  It also includes a top-level XML tag for
  53  * the rowset and three section tags identifying the three categories of values.
  54  * <P>
  55  * The tags in an XML document are hierarchical.
  56  * This means that the top-level tag, <code>RowSet</code>, is
  57  * followed by the three sections with appropriate tags, which are in turn each
  58  * followed by their constituent elements. For example, the <code>properties</code>
  59  * element will be followed by an element for each of the properties listed in
  60  * in this <code>XmlReaderContentHandler</code> object's <code>properties</code>
  61  * field.  The content of the other two fields, <code>colDef</code>, which lists
  62  * the rowset's metadata elements, and <code>data</code>, which lists the rowset's data
  63  * elements, are handled similarly .
  64  * <P>
  65  * This implementation of <code>XmlReaderContentHandler</code> provides the means for the
  66  * parser to determine which elements need to have a value set and then to set
  67  * those values. The methods in this class are all called by the parser; an
  68  * application programmer never calls them directly.
  69  *
  70  */
  71 
  72 public class XmlReaderContentHandler extends DefaultHandler {
  73 
  74     private HashMap propMap;
  75     private HashMap colDefMap;
  76     private HashMap dataMap;
  77 
  78     private HashMap typeMap;
  79 
  80     private Vector updates;
  81     private Vector keyCols;
  82 
  83     private String columnValue;
  84     private String propertyValue;
  85     private String metaDataValue;
  86 
  87     private int tag;
  88     private int state;
  89 
  90     private WebRowSetImpl rs;
  91     private boolean nullVal;
  92     private boolean emptyStringVal;
  93     private RowSetMetaData md;
  94     private int idx;
  95     private String lastval;
  96     private String Key_map;
  97     private String Value_map;
  98     private String tempStr;
  99     private String tempUpdate;
 100     private String tempCommand;
 101     private Object [] upd;
 102 
 103     /**
 104      * A list of the properties for a rowset. There is a constant defined to
 105      * correspond to each of these properties so that a <code>HashMap</code>
 106      * object can be created to map the properties, which are strings, to
 107      * the constants, which are integers.
 108      */
 109     private String [] properties = {"command", "concurrency", "datasource",
 110                             "escape-processing", "fetch-direction", "fetch-size",
 111                             "isolation-level", "key-columns", "map",
 112                             "max-field-size", "max-rows", "query-timeout",
 113                             "read-only", "rowset-type", "show-deleted",
 114                             "table-name", "url", "null", "column", "type",
 115                             "class", "sync-provider", "sync-provider-name",
 116                              "sync-provider-vendor", "sync-provider-version",
 117                              "sync-provider-grade","data-source-lock"};
 118 
 119     /**
 120      * A constant representing the tag for the command property.
 121      */
 122     private final static int CommandTag = 0;
 123 
 124     /**
 125      * A constant representing the tag for the concurrency property.
 126      */
 127     private final static int ConcurrencyTag = 1;
 128 
 129     /**
 130      * A constant representing the tag for the datasource property.
 131      */
 132     private final static int DatasourceTag = 2;
 133 
 134     /**
 135      * A constant representing the tag for the escape-processing property.
 136      */
 137     private final static int EscapeProcessingTag = 3;
 138 
 139     /**
 140      * A constant representing the tag for the fetch-direction property.
 141      */
 142     private final static int FetchDirectionTag = 4;
 143 
 144     /**
 145      * A constant representing the tag for the fetch-size property.
 146      */
 147     private final static int FetchSizeTag = 5;
 148 
 149     /**
 150      * A constant representing the tag for the isolation-level property
 151      */
 152     private final static int IsolationLevelTag = 6;
 153 
 154     /**
 155      * A constant representing the tag for the key-columns property.
 156      */
 157     private final static int KeycolsTag = 7;
 158 
 159     /**
 160      * A constant representing the tag for the map property.
 161      * This map is the type map that specifies the custom mapping
 162      * for an SQL user-defined type.
 163      */
 164     private final static int MapTag = 8;
 165 
 166     /**
 167      * A constant representing the tag for the max-field-size property.
 168      */
 169     private final static int MaxFieldSizeTag = 9;
 170 
 171     /**
 172      * A constant representing the tag for the max-rows property.
 173      */
 174     private final static int MaxRowsTag = 10;
 175 
 176     /**
 177      * A constant representing the tag for the query-timeout property.
 178      */
 179     private final static int QueryTimeoutTag = 11;
 180 
 181     /**
 182      * A constant representing the tag for the read-only property.
 183      */
 184     private final static int ReadOnlyTag = 12;
 185 
 186     /**
 187      * A constant representing the tag for the rowset-type property.
 188      */
 189     private final static int RowsetTypeTag = 13;
 190 
 191     /**
 192      * A constant representing the tag for the show-deleted property.
 193      */
 194     private final static int ShowDeletedTag = 14;
 195 
 196     /**
 197      * A constant representing the tag for the table-name property.
 198      */
 199     private final static int TableNameTag = 15;
 200 
 201     /**
 202      * A constant representing the tag for the URL property.
 203      */
 204     private final static int UrlTag = 16;
 205 
 206     /**
 207      * A constant representing the tag for the null property.
 208      */
 209     private final static int PropNullTag = 17;
 210 
 211     /**
 212      * A constant representing the tag for the column property.
 213      */
 214     private final static int PropColumnTag = 18;
 215 
 216     /**
 217      * A constant representing the tag for the type property.
 218      */
 219     private final static int PropTypeTag = 19;
 220 
 221     /**
 222      * A constant representing the tag for the class property.
 223      */
 224     private final static int PropClassTag = 20;
 225 
 226     /**
 227      * A constant representing the tag for the sync-provider.
 228      */
 229     private final static int SyncProviderTag = 21;
 230 
 231     /**
 232      * A constant representing the tag for the sync-provider
 233      * name
 234      */
 235     private final static int SyncProviderNameTag = 22;
 236 
 237     /**
 238      * A constant representing the tag for the sync-provider
 239      * vendor tag.
 240      */
 241     private final static int SyncProviderVendorTag = 23;
 242 
 243     /**
 244      * A constant representing the tag for the sync-provider
 245      * version tag.
 246      */
 247     private final static int SyncProviderVersionTag = 24;
 248 
 249     /**
 250      * A constant representing the tag for the sync-provider
 251      * grade tag.
 252      */
 253     private final static int SyncProviderGradeTag = 25;
 254 
 255     /**
 256      * A constant representing the tag for the data source lock.
 257      */
 258     private final static int DataSourceLock = 26;
 259 
 260     /**
 261      * A listing of the kinds of metadata information available about
 262      * the columns in a <code>WebRowSet</code> object.
 263      */
 264     private String [] colDef = {"column-count", "column-definition", "column-index",
 265                         "auto-increment", "case-sensitive", "currency",
 266                         "nullable", "signed", "searchable",
 267                         "column-display-size", "column-label", "column-name",
 268                         "schema-name", "column-precision", "column-scale",
 269                         "table-name", "catalog-name", "column-type",
 270                         "column-type-name", "null"};
 271 
 272 
 273     /**
 274      * A constant representing the tag for column-count.
 275      */
 276     private final static int ColumnCountTag = 0;
 277 
 278     /**
 279      * A constant representing the tag for column-definition.
 280      */
 281     private final static int ColumnDefinitionTag = 1;
 282 
 283     /**
 284      * A constant representing the tag for column-index.
 285      */
 286     private final static int ColumnIndexTag = 2;
 287 
 288     /**
 289      * A constant representing the tag for auto-increment.
 290      */
 291     private final static int AutoIncrementTag = 3;
 292 
 293     /**
 294      * A constant representing the tag for case-sensitive.
 295      */
 296     private final static int CaseSensitiveTag = 4;
 297 
 298     /**
 299      * A constant representing the tag for currency.
 300      */
 301     private final static int CurrencyTag = 5;
 302 
 303     /**
 304      * A constant representing the tag for nullable.
 305      */
 306     private final static int NullableTag = 6;
 307 
 308     /**
 309      * A constant representing the tag for signed.
 310      */
 311     private final static int SignedTag = 7;
 312 
 313     /**
 314      * A constant representing the tag for searchable.
 315      */
 316     private final static int SearchableTag = 8;
 317 
 318     /**
 319      * A constant representing the tag for column-display-size.
 320      */
 321     private final static int ColumnDisplaySizeTag = 9;
 322 
 323     /**
 324      * A constant representing the tag for column-label.
 325      */
 326     private final static int ColumnLabelTag = 10;
 327 
 328     /**
 329      * A constant representing the tag for column-name.
 330      */
 331     private final static int ColumnNameTag = 11;
 332 
 333     /**
 334      * A constant representing the tag for schema-name.
 335      */
 336     private final static int SchemaNameTag = 12;
 337 
 338     /**
 339      * A constant representing the tag for column-precision.
 340      */
 341     private final static int ColumnPrecisionTag = 13;
 342 
 343     /**
 344      * A constant representing the tag for column-scale.
 345      */
 346     private final static int ColumnScaleTag = 14;
 347 
 348     /**
 349      * A constant representing the tag for table-name.
 350      */
 351     private final static int MetaTableNameTag = 15;
 352 
 353     /**
 354      * A constant representing the tag for catalog-name.
 355      */
 356     private final static int CatalogNameTag = 16;
 357 
 358     /**
 359      * A constant representing the tag for column-type.
 360      */
 361     private final static int ColumnTypeTag = 17;
 362 
 363     /**
 364      * A constant representing the tag for column-type-name.
 365      */
 366     private final static int ColumnTypeNameTag = 18;
 367 
 368     /**
 369      * A constant representing the tag for null.
 370      */
 371     private final static int MetaNullTag = 19;
 372 
 373     private String [] data = {"currentRow", "columnValue", "insertRow", "deleteRow", "insdel", "updateRow", "null" , "emptyString"};
 374 
 375     private final static int RowTag = 0;
 376     private final static int ColTag = 1;
 377     private final static int InsTag = 2;
 378     private final static int DelTag = 3;
 379     private final static int InsDelTag = 4;
 380     private final static int UpdTag = 5;
 381     private final static int NullTag = 6;
 382     private final static int EmptyStringTag = 7;
 383 
 384     /**
 385      * A constant indicating the state of this <code>XmlReaderContentHandler</code>
 386      * object in which it has not yet been called by the SAX parser and therefore
 387      * has no indication of what type of input to expect from the parser next.
 388      * <P>
 389      * The state is set to <code>INITIAL</code> at the end of each
 390      * section, which allows the sections to appear in any order and
 391      * still be parsed correctly (except that metadata must be
 392      * set before data values can be set).
 393      */
 394     private final static int INITIAL = 0;
 395 
 396     /**
 397      * A constant indicating the state in which this <code>XmlReaderContentHandler</code>
 398      * object expects the next input received from the
 399      * SAX parser to be a string corresponding to one of the elements in
 400      * <code>properties</code>.
 401      */
 402     private final static int PROPERTIES = 1;
 403 
 404     /**
 405      * A constant indicating the state in which this <code>XmlReaderContentHandler</code>
 406      * object expects the next input received from the
 407      * SAX parser to be a string corresponding to one of the elements in
 408      * <code>colDef</code>.
 409      */
 410     private final static int METADATA = 2;
 411 
 412     /**
 413      * A constant indicating the state in which this <code>XmlReaderContentHandler</code>
 414      * object expects the next input received from the
 415      * SAX parser to be a string corresponding to one of the elements in
 416      * <code>data</code>.
 417      */
 418     private final static int DATA = 3;
 419 
 420     private  JdbcRowSetResourceBundle resBundle;
 421 
 422     /**
 423      * Constructs a new <code>XmlReaderContentHandler</code> object that will
 424      * assist the SAX parser in reading a <code>WebRowSet</code> object in the
 425      * format of an XML document. In addition to setting some default values,
 426      * this constructor creates three <code>HashMap</code> objects, one for
 427      * properties, one for metadata, and one for data.  These hash maps map the
 428      * strings sent by the SAX parser to integer constants so that they can be
 429      * compared more efficiently in <code>switch</code> statements.
 430      *
 431      * @param r the <code>RowSet</code> object in XML format that will be read
 432      */
 433     public XmlReaderContentHandler(RowSet r) {
 434         // keep the rowset we've been given
 435         rs = (WebRowSetImpl)r;
 436 
 437         // set-up the token maps
 438         initMaps();
 439 
 440         // allocate the collection for the updates
 441         updates = new Vector();
 442 
 443         // start out with the empty string
 444         columnValue = "";
 445         propertyValue = "";
 446         metaDataValue = "";
 447 
 448         nullVal = false;
 449         idx = 0;
 450         tempStr = "";
 451         tempUpdate = "";
 452         tempCommand = "";
 453 
 454         try {
 455            resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
 456         } catch(IOException ioe) {
 457             throw new RuntimeException(ioe);
 458         }
 459     }
 460 
 461     /**
 462      * Creates and initializes three new <code>HashMap</code> objects that map
 463      * the strings returned by the SAX parser to <code>Integer</code>
 464      * objects.  The strings returned by the parser will match the strings that
 465      * are array elements in this <code>XmlReaderContentHandler</code> object's
 466      * <code>properties</code>, <code>colDef</code>, or <code>data</code>
 467      * fields. For each array element in these fields, there is a corresponding
 468      * constant defined. It is to these constants that the strings are mapped.
 469      * In the <code>HashMap</code> objects, the string is the key, and the
 470      * integer is the value.
 471      * <P>
 472      * The purpose of the mapping is to make comparisons faster.  Because comparing
 473      * numbers is more efficient than comparing strings, the strings returned
 474      * by the parser are mapped to integers, which can then be used in a
 475      * <code>switch</code> statement.
 476      */
 477     private void initMaps() {
 478         int items, i;
 479 
 480         propMap = new HashMap();
 481         items = properties.length;
 482 
 483         for (i=0;i<items;i++) {
 484             propMap.put(properties[i], Integer.valueOf(i));
 485         }
 486 
 487         colDefMap = new HashMap();
 488         items = colDef.length;
 489 
 490         for (i=0;i<items;i++) {
 491             colDefMap.put(colDef[i], Integer.valueOf(i));
 492         }
 493 
 494         dataMap = new HashMap();
 495         items = data.length;
 496 
 497         for (i=0;i<items;i++) {
 498             dataMap.put(data[i], Integer.valueOf(i));
 499         }
 500 
 501         //Initialize connection map here
 502         typeMap = new HashMap();
 503     }
 504 
 505     public void startDocument() throws SAXException {
 506     }
 507 
 508     public void endDocument() throws SAXException {
 509     }
 510 
 511 
 512     /**
 513      * Sets this <code>XmlReaderContentHandler</code> object's <code>tag</code>
 514      * field if the given name is the key for a tag and this object's state
 515      * is not <code>INITIAL</code>.  The field is set
 516      * to the constant that corresponds to the given element name.
 517      * If the state is <code>INITIAL</code>, the state is set to the given
 518      * name, which will be one of the sections <code>PROPERTIES</code>,
 519      * <code>METADATA</code>, or <code>DATA</code>.  In either case, this
 520      * method puts this document handler in the proper state for calling
 521      * the method <code>endElement</code>.
 522      * <P>
 523      * If the state is <code>DATA</code> and the tag is <code>RowTag</code>,
 524      * <code>DelTag</code>, or <code>InsTag</code>, this method moves the
 525      * rowset's cursor to the insert row and sets this
 526      * <code>XmlReaderContentHandler</code> object's <code>idx</code>
 527      * field to <code>0</code> so that it will be in the proper
 528      * state when the parser calls the method <code>endElement</code>.
 529      *
 530      * @param lName the name of the element; either (1) one of the array
 531      *        elements in the fields <code>properties</code>,
 532      *        <code>colDef</code>, or <code>data</code> or
 533      *        (2) one of the <code>RowSet</code> elements
 534      *        <code>"properties"</code>, <code>"metadata"</code>, or
 535      *        <code>"data"</code>
 536      * @param attributes <code>org.xml.sax.AttributeList</code> objects that are
 537      *             attributes of the named section element; may be <code>null</code>
 538      *             if there are no attributes, which is the case for
 539      *             <code>WebRowSet</code> objects
 540      * @exception SAXException if a general SAX error occurs
 541      */
 542     public void startElement(String uri, String lName, String qName, Attributes attributes) throws SAXException {
 543         int tag;
 544         String name = "";
 545 
 546         name = lName;
 547 
 548         switch (getState()) {
 549         case PROPERTIES:
 550 
 551             tempCommand = "";
 552             tag = ((Integer)propMap.get(name)).intValue();
 553             if (tag == PropNullTag)
 554                setNullValue(true);
 555             else
 556                 setTag(tag);
 557             break;
 558         case METADATA:
 559             tag = ((Integer)colDefMap.get(name)).intValue();
 560 
 561             if (tag == MetaNullTag)
 562                 setNullValue(true);
 563             else
 564                 setTag(tag);
 565             break;
 566         case DATA:
 567 
 568             /**
 569               * This has been added to clear out the values of the previous read
 570               * so that we should not add up values of data between different tags
 571               */
 572             tempStr = "";
 573             tempUpdate = "";
 574             if(dataMap.get(name) == null) {
 575                 tag = NullTag;
 576             } else if(((Integer)dataMap.get(name)).intValue() == EmptyStringTag) {
 577                 tag = EmptyStringTag;
 578             } else {
 579                  tag = ((Integer)dataMap.get(name)).intValue();
 580             }
 581 
 582             if (tag == NullTag) {
 583                 setNullValue(true);
 584             } else if(tag == EmptyStringTag) {
 585                 setEmptyStringValue(true);
 586             } else {
 587                 setTag(tag);
 588 
 589                 if (tag == RowTag || tag == DelTag || tag == InsTag) {
 590                     idx = 0;
 591                     try {
 592                         rs.moveToInsertRow();
 593                     } catch (SQLException ex) {
 594                         ;
 595                     }
 596                 }
 597             }
 598 
 599             break;
 600         default:
 601             setState(name);
 602         }
 603 
 604     }
 605 
 606     /**
 607      * Sets the value for the given element if <code>name</code> is one of
 608      * the array elements in the fields <code>properties</code>,
 609      * <code>colDef</code>, or <code>data</code> and this
 610      * <code>XmlReaderContentHandler</code> object's state is not
 611      * <code>INITIAL</code>. If the state is <code>INITIAL</code>,
 612      * this method does nothing.
 613      * <P>
 614      * If the state is <code>METADATA</code> and
 615      * the argument supplied is <code>"metadata"</code>, the rowset's
 616      * metadata is set. If the state is <code>PROPERTIES</code>, the
 617      * appropriate property is set using the given name to determine
 618      * the appropriate value. If the state is <code>DATA</code> and
 619      * the argument supplied is <code>"data"</code>, this method sets
 620      * the state to <code>INITIAL</code> and returns.  If the argument
 621      * supplied is one of the elements in the field <code>data</code>,
 622      * this method makes the appropriate changes to the rowset's data.
 623      *
 624      * @param lName the name of the element; either (1) one of the array
 625      *        elements in the fields <code>properties</code>,
 626      *        <code>colDef</code>, or <code>data</code> or
 627      *        (2) one of the <code>RowSet</code> elements
 628      *        <code>"properties"</code>, <code>"metadata"</code>, or
 629      *        <code>"data"</code>
 630      *
 631      * @exception SAXException if a general SAX error occurs
 632      */
 633     public void endElement(String uri, String lName, String qName) throws SAXException {
 634         int tag;
 635 
 636         String name = "";
 637         name = lName;
 638 
 639         switch (getState()) {
 640         case PROPERTIES:
 641             if (name.equals("properties")) {
 642                 state = INITIAL;
 643                 break;
 644             }
 645 
 646             try {
 647                 tag = ((Integer)propMap.get(name)).intValue();
 648                 switch (tag) {
 649                 case KeycolsTag:
 650                     if (keyCols != null) {
 651                         int i[] = new int[keyCols.size()];
 652                         for (int j = 0; j < i.length; j++)
 653                             i[j] = Integer.parseInt((String)keyCols.elementAt(j));
 654                         rs.setKeyColumns(i);
 655                     }
 656                     break;
 657 
 658                  case PropClassTag:
 659                      //Added the handling for Class tags to take care of maps
 660                      //Makes an entry into the map upon end of class tag
 661                      try{
 662                           typeMap.put(Key_map,Class.forName(Value_map));
 663 
 664                         }catch(ClassNotFoundException ex) {
 665                           throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errmap").toString(), ex.getMessage()));
 666                         }
 667                       break;
 668 
 669                  case MapTag:
 670                       //Added the handling for Map to take set the typeMap
 671                       rs.setTypeMap(typeMap);
 672                       break;
 673 
 674                 default:
 675                     break;
 676                 }
 677 
 678                 if (getNullValue()) {
 679                     setPropertyValue(null);
 680                     setNullValue(false);
 681                 } else {
 682                     setPropertyValue(propertyValue);
 683                 }
 684             } catch (SQLException ex) {
 685                 throw new SAXException(ex.getMessage());
 686             }
 687 
 688             // propertyValue need to be reset to an empty string
 689             propertyValue = "";
 690             setTag(-1);
 691             break;
 692         case METADATA:
 693             if (name.equals("metadata")) {
 694                 try {
 695                     rs.setMetaData(md);
 696                     state = INITIAL;
 697                 } catch (SQLException ex) {
 698                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errmetadata").toString(), ex.getMessage()));
 699                 }
 700             } else {
 701                 try {
 702                     if (getNullValue()) {
 703                         setMetaDataValue(null);
 704                         setNullValue(false);
 705                     } else {
 706                         setMetaDataValue(metaDataValue);
 707                     }
 708                 } catch (SQLException ex) {
 709                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errmetadata").toString(), ex.getMessage()));
 710 
 711                 }
 712                 // metaDataValue needs to be reset to an empty string
 713                 metaDataValue = "";
 714             }
 715             setTag(-1);
 716             break;
 717         case DATA:
 718             if (name.equals("data")) {
 719                 state = INITIAL;
 720                 return;
 721             }
 722 
 723             if(dataMap.get(name) == null) {
 724                 tag = NullTag;
 725             } else {
 726                  tag = ((Integer)dataMap.get(name)).intValue();
 727             }
 728             switch (tag) {
 729             case ColTag:
 730                 try {
 731                     idx++;
 732                     if (getNullValue()) {
 733                         insertValue(null);
 734                         setNullValue(false);
 735                     } else {
 736                         insertValue(tempStr);
 737                     }
 738                     // columnValue now need to be reset to the empty string
 739                     columnValue = "";
 740                 } catch (SQLException ex) {
 741                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errinsertval").toString(), ex.getMessage()));
 742                 }
 743                 break;
 744             case RowTag:
 745                 try {
 746                     rs.insertRow();
 747                     rs.moveToCurrentRow();
 748                     rs.next();
 749 
 750                     // Making this as the original to turn off the
 751                     // rowInserted flagging
 752                     rs.setOriginalRow();
 753 
 754                     applyUpdates();
 755                 } catch (SQLException ex) {
 756                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errconstr").toString(), ex.getMessage()));
 757                 }
 758                 break;
 759             case DelTag:
 760                 try {
 761                     rs.insertRow();
 762                     rs.moveToCurrentRow();
 763                     rs.next();
 764                     rs.setOriginalRow();
 765                     applyUpdates();
 766                 } catch (SQLException ex) {
 767                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errdel").toString() , ex.getMessage()));
 768                 }
 769                 break;
 770             case InsTag:
 771                 try {
 772                     rs.insertRow();
 773                     rs.moveToCurrentRow();
 774                     rs.next();
 775                     applyUpdates();
 776                 } catch (SQLException ex) {
 777                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errinsert").toString() , ex.getMessage()));
 778                 }
 779                 break;
 780 
 781             case InsDelTag:
 782                 try {
 783                     rs.insertRow();
 784                     rs.moveToCurrentRow();
 785                     rs.next();
 786                     rs.setOriginalRow();
 787                     applyUpdates();
 788                 } catch (SQLException ex) {
 789                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errinsdel").toString() , ex.getMessage()));
 790                 }
 791                 break;
 792 
 793              case UpdTag:
 794                  try {
 795                         if(getNullValue())
 796                          {
 797                           insertValue(null);
 798                           setNullValue(false);
 799                          } else if(getEmptyStringValue()) {
 800                                insertValue("");
 801                                setEmptyStringValue(false);
 802                          } else {
 803                             updates.add(upd);
 804                          }
 805                  }  catch(SQLException ex) {
 806                         throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errupdate").toString() , ex.getMessage()));
 807                  }
 808                 break;
 809 
 810             default:
 811                 break;
 812             }
 813         default:
 814             break;
 815         }
 816     }
 817 
 818     private void applyUpdates() throws SAXException {
 819         // now handle any updates
 820         if (updates.size() > 0) {
 821             try {
 822                 Object upd[];
 823                 Iterator i = updates.iterator();
 824                 while (i.hasNext()) {
 825                     upd = (Object [])i.next();
 826                     idx = ((Integer)upd[0]).intValue();
 827 
 828                    if(!(lastval.equals(upd[1]))){
 829                        insertValue((String)(upd[1]));
 830                     }
 831                 }
 832 
 833                 rs.updateRow();
 834                 } catch (SQLException ex) {
 835                     throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errupdrow").toString() , ex.getMessage()));
 836                 }
 837             updates.removeAllElements();
 838         }
 839 
 840 
 841     }
 842 
 843     /**
 844      * Sets a property, metadata, or data value with the characters in
 845      * the given array of characters, starting with the array element
 846      * indicated by <code>start</code> and continuing for <code>length</code>
 847      * number of characters.
 848      * <P>
 849      * The SAX parser invokes this method and supplies
 850      * the character array, start position, and length parameter values it
 851      * got from parsing the XML document.  An application programmer never
 852      * invokes this method directly.
 853      *
 854      * @param ch an array of characters supplied by the SAX parser, all or part of
 855      *         which will be used to set a value
 856      * @param start the position in the given array at which to start
 857      * @param length the number of consecutive characters to use
 858      */
 859     public void characters(char[] ch, int start, int length) throws SAXException {
 860         try {
 861             switch (getState()) {
 862             case PROPERTIES:
 863                 propertyValue = new String(ch, start, length);
 864 
 865                 /**
 866                   * This has been added for handling of special characters. When special
 867                   * characters are encountered the characters function gets called for
 868                   * each of the characters so we need to append the value got in the
 869                   * previous call as it is the same data present between the start and
 870                   * the end tag.
 871                   **/
 872                 tempCommand = tempCommand.concat(propertyValue);
 873                 propertyValue = tempCommand;
 874 
 875                 // Added the following check for handling of type tags in maps
 876                 if(tag == PropTypeTag)
 877                 {
 878                         Key_map = propertyValue;
 879                 }
 880 
 881                 // Added the following check for handling of class tags in maps
 882                 else if(tag == PropClassTag)
 883                 {
 884                         Value_map = propertyValue;
 885                 }
 886                 break;
 887 
 888             case METADATA:
 889 
 890                 // The parser will come here after the endElement as there is
 891                 // "\n" in the after endTag is printed. This will cause a problem
 892                 // when the data between the tags is an empty string so adding
 893                 // below condition to take care of that situation.
 894 
 895                 if (tag == -1)
 896                 {
 897                         break;
 898                 }
 899 
 900                 metaDataValue = new String(ch, start, length);
 901                 break;
 902             case DATA:
 903                 setDataValue(ch, start, length);
 904                 break;
 905             default:
 906                 ;
 907             }
 908         } catch (SQLException ex) {
 909             throw new SAXException(resBundle.handleGetObject("xmlrch.chars").toString() + ex.getMessage());
 910         }
 911     }
 912 
 913     private void setState(String s) throws SAXException {
 914         if (s.equals("webRowSet")) {
 915             state = INITIAL;
 916         } else if (s.equals("properties")) {
 917             if (state != PROPERTIES)
 918                 state = PROPERTIES;
 919             else
 920                 state = INITIAL;
 921         } else if (s.equals("metadata")) {
 922             if (state != METADATA)
 923                 state = METADATA;
 924             else
 925                 state = INITIAL;
 926         } else if (s.equals("data")) {
 927             if (state != DATA)
 928                 state = DATA;
 929             else
 930                 state = INITIAL;
 931         }
 932 
 933     }
 934 
 935     /**
 936      * Retrieves the current state of this <code>XmlReaderContentHandler</code>
 937      * object's rowset, which is stored in the document handler's
 938      * <code>state</code> field.
 939      *
 940      * @return one of the following constants:
 941      *         <code>XmlReaderContentHandler.PROPERTIES</code>
 942      *         <code>XmlReaderContentHandler.METADATA</code>
 943      *         <code>XmlReaderContentHandler.DATA</code>
 944      *         <code>XmlReaderContentHandler.INITIAL</code>
 945      */
 946     private int getState() {
 947         return state;
 948     }
 949 
 950     private void setTag(int t) {
 951         tag = t;
 952     }
 953 
 954     private int getTag() {
 955         return tag;
 956     }
 957 
 958     private void setNullValue(boolean n) {
 959         nullVal = n;
 960     }
 961 
 962     private boolean getNullValue() {
 963         return nullVal;
 964     }
 965 
 966     private void setEmptyStringValue(boolean e) {
 967         emptyStringVal = e;
 968     }
 969 
 970     private boolean getEmptyStringValue() {
 971         return emptyStringVal;
 972     }
 973 
 974     private String getStringValue(String s) {
 975          return s;
 976     }
 977 
 978     private int getIntegerValue(String s) {
 979         return Integer.parseInt(s);
 980     }
 981 
 982     private boolean getBooleanValue(String s) {
 983 
 984         return Boolean.valueOf(s).booleanValue();
 985     }
 986 
 987     private java.math.BigDecimal getBigDecimalValue(String s) {
 988         return new java.math.BigDecimal(s);
 989     }
 990 
 991     private byte getByteValue(String s) {
 992         return Byte.parseByte(s);
 993     }
 994 
 995     private short getShortValue(String s) {
 996         return Short.parseShort(s);
 997     }
 998 
 999     private long getLongValue(String s) {
1000         return Long.parseLong(s);
1001     }
1002 
1003     private float getFloatValue(String s) {
1004         return Float.parseFloat(s);
1005     }
1006 
1007     private double getDoubleValue(String s) {
1008         return Double.parseDouble(s);
1009     }
1010 
1011     private byte[] getBinaryValue(String s) {
1012         return s.getBytes();
1013     }
1014 
1015     private java.sql.Date getDateValue(String s) {
1016         return new java.sql.Date(getLongValue(s));
1017     }
1018 
1019     private java.sql.Time getTimeValue(String s) {
1020         return new java.sql.Time(getLongValue(s));
1021     }
1022 
1023     private java.sql.Timestamp getTimestampValue(String s) {
1024         return new java.sql.Timestamp(getLongValue(s));
1025     }
1026 
1027     private void setPropertyValue(String s) throws SQLException {
1028         // find out if we are going to be dealing with a null
1029         boolean nullValue = getNullValue();
1030 
1031         switch(getTag()) {
1032         case CommandTag:
1033             if (nullValue)
1034                ; //rs.setCommand(null);
1035             else
1036                 rs.setCommand(s);
1037             break;
1038         case ConcurrencyTag:
1039             if (nullValue)
1040                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1041             else
1042                 rs.setConcurrency(getIntegerValue(s));
1043             break;
1044         case DatasourceTag:
1045             if (nullValue)
1046                 rs.setDataSourceName(null);
1047             else
1048                 rs.setDataSourceName(s);
1049             break;
1050         case EscapeProcessingTag:
1051             if (nullValue)
1052                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1053             else
1054                 rs.setEscapeProcessing(getBooleanValue(s));
1055             break;
1056         case FetchDirectionTag:
1057             if (nullValue)
1058                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1059             else
1060                 rs.setFetchDirection(getIntegerValue(s));
1061             break;
1062         case FetchSizeTag:
1063             if (nullValue)
1064                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1065             else
1066                 rs.setFetchSize(getIntegerValue(s));
1067             break;
1068         case IsolationLevelTag:
1069             if (nullValue)
1070                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1071             else
1072                 rs.setTransactionIsolation(getIntegerValue(s));
1073             break;
1074         case KeycolsTag:
1075             break;
1076         case PropColumnTag:
1077             if (keyCols == null)
1078                 keyCols = new Vector();
1079             keyCols.add(s);
1080             break;
1081         case MapTag:
1082             break;
1083         case MaxFieldSizeTag:
1084             if (nullValue)
1085                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1086             else
1087                 rs.setMaxFieldSize(getIntegerValue(s));
1088             break;
1089         case MaxRowsTag:
1090             if (nullValue)
1091                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1092             else
1093                 rs.setMaxRows(getIntegerValue(s));
1094             break;
1095         case QueryTimeoutTag:
1096             if (nullValue)
1097                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1098             else
1099                 rs.setQueryTimeout(getIntegerValue(s));
1100             break;
1101         case ReadOnlyTag:
1102             if (nullValue)
1103                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1104             else
1105                 rs.setReadOnly(getBooleanValue(s));
1106             break;
1107         case RowsetTypeTag:
1108             if (nullValue) {
1109                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1110             } else {
1111                 //rs.setType(getIntegerValue(s));
1112                 String strType = getStringValue(s);
1113                 int iType = 0;
1114 
1115                 if(strType.trim().equals("ResultSet.TYPE_SCROLL_INSENSITIVE")) {
1116                    iType = 1004;
1117                 } else if(strType.trim().equals("ResultSet.TYPE_SCROLL_SENSITIVE"))   {
1118                    iType = 1005;
1119                 } else if(strType.trim().equals("ResultSet.TYPE_FORWARD_ONLY")) {
1120                    iType = 1003;
1121                 }
1122                 rs.setType(iType);
1123             }
1124             break;
1125         case ShowDeletedTag:
1126             if (nullValue)
1127                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString());
1128             else
1129                 rs.setShowDeleted(getBooleanValue(s));
1130             break;
1131         case TableNameTag:
1132             if (nullValue)
1133                 //rs.setTableName(null);
1134                 ;
1135             else
1136                 rs.setTableName(s);
1137             break;
1138         case UrlTag:
1139             if (nullValue)
1140                 rs.setUrl(null);
1141             else
1142                 rs.setUrl(s);
1143             break;
1144         case SyncProviderNameTag:
1145             if (nullValue) {
1146                 rs.setSyncProvider(null);
1147             } else {
1148                 String str = s.substring(0,s.indexOf("@")+1);
1149                 rs.setSyncProvider(str);
1150             }
1151             break;
1152         case SyncProviderVendorTag:
1153             // to be implemented
1154             break;
1155         case SyncProviderVersionTag:
1156             // to be implemented
1157             break;
1158         case SyncProviderGradeTag:
1159             // to be implemented
1160             break;
1161         case DataSourceLock:
1162             // to be implemented
1163             break;
1164         default:
1165             break;
1166         }
1167 
1168     }
1169 
1170     private void setMetaDataValue(String s) throws SQLException {
1171         // find out if we are going to be dealing with a null
1172         boolean nullValue = getNullValue();
1173 
1174         switch (getTag()) {
1175         case ColumnCountTag:
1176             md = new RowSetMetaDataImpl();
1177             idx = 0;
1178 
1179             if (nullValue) {
1180                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1181             } else {
1182                 md.setColumnCount(getIntegerValue(s));
1183             }
1184             break;
1185         case ColumnDefinitionTag:
1186             break;
1187         case ColumnIndexTag:
1188             idx++;
1189             break;
1190         case AutoIncrementTag:
1191             if (nullValue)
1192                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1193             else
1194                 md.setAutoIncrement(idx, getBooleanValue(s));
1195             break;
1196         case CaseSensitiveTag:
1197             if (nullValue)
1198                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1199             else
1200                 md.setCaseSensitive(idx, getBooleanValue(s));
1201             break;
1202         case CurrencyTag:
1203             if (nullValue)
1204                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1205             else
1206                 md.setCurrency(idx, getBooleanValue(s));
1207             break;
1208         case NullableTag:
1209             if (nullValue)
1210                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1211             else
1212                 md.setNullable(idx, getIntegerValue(s));
1213             break;
1214         case SignedTag:
1215             if (nullValue)
1216                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1217             else
1218                 md.setSigned(idx, getBooleanValue(s));
1219             break;
1220         case SearchableTag:
1221             if (nullValue)
1222                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1223             else
1224                 md.setSearchable(idx, getBooleanValue(s));
1225             break;
1226         case ColumnDisplaySizeTag:
1227             if (nullValue)
1228                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1229             else
1230                 md.setColumnDisplaySize(idx, getIntegerValue(s));
1231             break;
1232         case ColumnLabelTag:
1233             if (nullValue)
1234                 md.setColumnLabel(idx, null);
1235             else
1236                 md.setColumnLabel(idx, s);
1237             break;
1238         case ColumnNameTag:
1239             if (nullValue)
1240                 md.setColumnName(idx, null);
1241             else
1242                 md.setColumnName(idx, s);
1243 
1244             break;
1245         case SchemaNameTag:
1246             if (nullValue) {
1247                 md.setSchemaName(idx, null); }
1248             else
1249                 md.setSchemaName(idx, s);
1250             break;
1251         case ColumnPrecisionTag:
1252             if (nullValue)
1253                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1254             else
1255                 md.setPrecision(idx, getIntegerValue(s));
1256             break;
1257         case ColumnScaleTag:
1258             if (nullValue)
1259                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1260             else
1261                 md.setScale(idx, getIntegerValue(s));
1262             break;
1263         case MetaTableNameTag:
1264             if (nullValue)
1265                 md.setTableName(idx, null);
1266             else
1267                 md.setTableName(idx, s);
1268             break;
1269         case CatalogNameTag:
1270             if (nullValue)
1271                 md.setCatalogName(idx, null);
1272             else
1273                 md.setCatalogName(idx, s);
1274             break;
1275         case ColumnTypeTag:
1276             if (nullValue)
1277                 throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString());
1278             else
1279                 md.setColumnType(idx, getIntegerValue(s));
1280             break;
1281         case ColumnTypeNameTag:
1282             if (nullValue)
1283                 md.setColumnTypeName(idx, null);
1284             else
1285                 md.setColumnTypeName(idx, s);
1286             break;
1287         default:
1288             //System.out.println("MetaData: Unknown Tag: (" + getTag() + ")");
1289             break;
1290 
1291         }
1292     }
1293 
1294     private void setDataValue(char[] ch, int start, int len) throws SQLException {
1295         switch (getTag()) {
1296         case ColTag:
1297             columnValue = new String(ch, start, len);
1298             /**
1299               * This has been added for handling of special characters. When special
1300               * characters are encountered the characters function gets called for
1301               * each of the characters so we need to append the value got in the
1302               * previous call as it is the same data present between the start and
1303               * the end tag.
1304               **/
1305             tempStr = tempStr.concat(columnValue);
1306             break;
1307         case UpdTag:
1308             upd = new Object[2];
1309 
1310             /**
1311               * This has been added for handling of special characters. When special
1312               * characters are encountered the characters function gets called for
1313               * each of the characters so we need to append the value got in the
1314               * previous call as it is the same data present between the start and
1315               * the end tag.
1316               **/
1317 
1318             tempUpdate = tempUpdate.concat(new String(ch,start,len));
1319             upd[0] = Integer.valueOf(idx);
1320             upd[1] = tempUpdate;
1321             //updates.add(upd);
1322 
1323             lastval = (String)upd[1];
1324             //insertValue(ch, start, len);
1325             break;
1326         case InsTag:
1327 
1328         }
1329     }
1330 
1331     private void insertValue(String s) throws SQLException {
1332 
1333         if (getNullValue()) {
1334             rs.updateNull(idx);
1335             return;
1336         }
1337 
1338         // no longer have to deal with those pesky nulls.
1339         int type = rs.getMetaData().getColumnType(idx);
1340         switch (type) {
1341         case java.sql.Types.BIT:
1342             rs.updateBoolean(idx, getBooleanValue(s));
1343             break;
1344         case java.sql.Types.BOOLEAN:
1345             rs.updateBoolean(idx, getBooleanValue(s));
1346             break;
1347         case java.sql.Types.SMALLINT:
1348         case java.sql.Types.TINYINT:
1349             rs.updateShort(idx, getShortValue(s));
1350             break;
1351         case java.sql.Types.INTEGER:
1352             rs.updateInt(idx, getIntegerValue(s));
1353             break;
1354         case java.sql.Types.BIGINT:
1355             rs.updateLong(idx, getLongValue(s));
1356             break;
1357         case java.sql.Types.REAL:
1358         case java.sql.Types.FLOAT:
1359             rs.updateFloat(idx, getFloatValue(s));
1360             break;
1361         case java.sql.Types.DOUBLE:
1362             rs.updateDouble(idx, getDoubleValue(s));
1363             break;
1364         case java.sql.Types.NUMERIC:
1365         case java.sql.Types.DECIMAL:
1366             rs.updateObject(idx, getBigDecimalValue(s));
1367             break;
1368         case java.sql.Types.BINARY:
1369         case java.sql.Types.VARBINARY:
1370         case java.sql.Types.LONGVARBINARY:
1371             rs.updateBytes(idx, getBinaryValue(s));
1372             break;
1373         case java.sql.Types.DATE:
1374             rs.updateDate(idx,  getDateValue(s));
1375             break;
1376         case java.sql.Types.TIME:
1377             rs.updateTime(idx, getTimeValue(s));
1378             break;
1379         case java.sql.Types.TIMESTAMP:
1380             rs.updateTimestamp(idx, getTimestampValue(s));
1381             break;
1382         case java.sql.Types.CHAR:
1383         case java.sql.Types.VARCHAR:
1384         case java.sql.Types.LONGVARCHAR:
1385             rs.updateString(idx, getStringValue(s));
1386             break;
1387         default:
1388 
1389         }
1390 
1391     }
1392 
1393     /**
1394      * Throws the given <code>SAXParseException</code> object. This
1395      * exception was originally thrown by the SAX parser and is passed
1396      * to the method <code>error</code> when the SAX parser invokes it.
1397      *
1398      * @param e the <code>SAXParseException</code> object to throw
1399      */
1400     public void error (SAXParseException e) throws SAXParseException {
1401             throw e;
1402     }
1403 
1404     // dump warnings too
1405     /**
1406      * Prints a warning message to <code>System.out</code> giving the line
1407      * number and uri for what caused the warning plus a message explaining
1408      * the reason for the warning. This method is invoked by the SAX parser.
1409      *
1410      * @param err a warning generated by the SAX parser
1411      */
1412     public void warning (SAXParseException err) throws SAXParseException {
1413         System.out.println (MessageFormat.format(resBundle.handleGetObject("xmlrch.warning").toString(), new Object[] { err.getMessage(), err.getLineNumber(), err.getSystemId() }));
1414     }
1415 
1416     /**
1417      *
1418      */
1419     public void notationDecl(String name, String publicId, String systemId) {
1420 
1421     }
1422 
1423     /**
1424      *
1425      */
1426     public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) {
1427 
1428     }
1429 
1430    /**
1431     * Returns the current row of this <code>Rowset</code>object.
1432     * The ResultSet's cursor is positioned at the Row which is needed
1433     *
1434     * @return the <code>Row</code> object on which the <code>RowSet</code>
1435     *           implementation objects's cursor is positioned
1436     */
1437     private Row getPresentRow(WebRowSetImpl rs) throws SQLException {
1438          //rs.setOriginalRow();
1439          // ResultSetMetaData rsmd = rs.getMetaData();
1440          // int numCols = rsmd.getColumnCount();
1441          // Object vals[] = new Object[numCols];
1442          // for(int j = 1; j<= numCols ; j++){
1443          //     vals[j-1] = rs.getObject(j);
1444          // }
1445          // return(new Row(numCols, vals));
1446          return null;
1447    }
1448 
1449 
1450 
1451 
1452 }