1 /* 2 * Copyright (c) 2003, 2010, 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 }