blob: 4663739c7f5672e599d2ef93cdb33ba5a06a88e1 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.rowset.internal;
27
28import java.util.*;
29
30import org.xml.sax.*;
31import org.xml.sax.helpers.*;
32
33import java.sql.*;
34import javax.sql.*;
35
36import javax.sql.rowset.*;
37import com.sun.rowset.*;
38import java.io.IOException;
39import 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
72public 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 = new String("");
445 propertyValue = new String("");
446 metaDataValue = new String("");
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], new Integer(i));
485 }
486
487 colDefMap = new HashMap();
488 items = colDef.length;
489
490 for (i=0;i<items;i++) {
491 colDefMap.put(colDef[i], new Integer(i));
492 }
493
494 dataMap = new HashMap();
495 items = data.length;
496
497 for (i=0;i<items;i++) {
498 dataMap.put(data[i], new Integer(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 = new String("");
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 = new String("");
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 = new String("");
740 } catch (SQLException ex) {
741 throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errinsert").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 new Boolean(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] = new Integer(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}