| /* |
| * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.rowset.internal; |
| |
| import java.util.*; |
| |
| import org.xml.sax.*; |
| import org.xml.sax.helpers.*; |
| |
| import java.sql.*; |
| import javax.sql.*; |
| |
| import javax.sql.rowset.*; |
| import com.sun.rowset.*; |
| import java.io.IOException; |
| import java.text.MessageFormat; |
| |
| /** |
| * The document handler that receives parse events that an XML parser sends while it |
| * is parsing an XML document representing a <code>WebRowSet</code> object. The |
| * parser sends strings to this <code>XmlReaderContentHandler</code> and then uses |
| * these strings as arguments for the <code>XmlReaderContentHandler</code> methods |
| * it invokes. The final goal of the SAX parser working with an |
| * <code>XmlReaderContentHandler</code> object is to read an XML document that represents |
| * a <code>RowSet</code> object. |
| * <P> |
| * A rowset consists of its properties, metadata, and data values. An XML document |
| * representating a rowset includes the values in these three categories along with |
| * appropriate XML tags to identify them. It also includes a top-level XML tag for |
| * the rowset and three section tags identifying the three categories of values. |
| * <P> |
| * The tags in an XML document are hierarchical. |
| * This means that the top-level tag, <code>RowSet</code>, is |
| * followed by the three sections with appropriate tags, which are in turn each |
| * followed by their constituent elements. For example, the <code>properties</code> |
| * element will be followed by an element for each of the properties listed in |
| * in this <code>XmlReaderContentHandler</code> object's <code>properties</code> |
| * field. The content of the other two fields, <code>colDef</code>, which lists |
| * the rowset's metadata elements, and <code>data</code>, which lists the rowset's data |
| * elements, are handled similarly . |
| * <P> |
| * This implementation of <code>XmlReaderContentHandler</code> provides the means for the |
| * parser to determine which elements need to have a value set and then to set |
| * those values. The methods in this class are all called by the parser; an |
| * application programmer never calls them directly. |
| * |
| */ |
| |
| public class XmlReaderContentHandler extends DefaultHandler { |
| |
| private HashMap propMap; |
| private HashMap colDefMap; |
| private HashMap dataMap; |
| |
| private HashMap typeMap; |
| |
| private Vector updates; |
| private Vector keyCols; |
| |
| private String columnValue; |
| private String propertyValue; |
| private String metaDataValue; |
| |
| private int tag; |
| private int state; |
| |
| private WebRowSetImpl rs; |
| private boolean nullVal; |
| private boolean emptyStringVal; |
| private RowSetMetaData md; |
| private int idx; |
| private String lastval; |
| private String Key_map; |
| private String Value_map; |
| private String tempStr; |
| private String tempUpdate; |
| private String tempCommand; |
| private Object [] upd; |
| |
| /** |
| * A list of the properties for a rowset. There is a constant defined to |
| * correspond to each of these properties so that a <code>HashMap</code> |
| * object can be created to map the properties, which are strings, to |
| * the constants, which are integers. |
| */ |
| private String [] properties = {"command", "concurrency", "datasource", |
| "escape-processing", "fetch-direction", "fetch-size", |
| "isolation-level", "key-columns", "map", |
| "max-field-size", "max-rows", "query-timeout", |
| "read-only", "rowset-type", "show-deleted", |
| "table-name", "url", "null", "column", "type", |
| "class", "sync-provider", "sync-provider-name", |
| "sync-provider-vendor", "sync-provider-version", |
| "sync-provider-grade","data-source-lock"}; |
| |
| /** |
| * A constant representing the tag for the command property. |
| */ |
| private final static int CommandTag = 0; |
| |
| /** |
| * A constant representing the tag for the concurrency property. |
| */ |
| private final static int ConcurrencyTag = 1; |
| |
| /** |
| * A constant representing the tag for the datasource property. |
| */ |
| private final static int DatasourceTag = 2; |
| |
| /** |
| * A constant representing the tag for the escape-processing property. |
| */ |
| private final static int EscapeProcessingTag = 3; |
| |
| /** |
| * A constant representing the tag for the fetch-direction property. |
| */ |
| private final static int FetchDirectionTag = 4; |
| |
| /** |
| * A constant representing the tag for the fetch-size property. |
| */ |
| private final static int FetchSizeTag = 5; |
| |
| /** |
| * A constant representing the tag for the isolation-level property |
| */ |
| private final static int IsolationLevelTag = 6; |
| |
| /** |
| * A constant representing the tag for the key-columns property. |
| */ |
| private final static int KeycolsTag = 7; |
| |
| /** |
| * A constant representing the tag for the map property. |
| * This map is the type map that specifies the custom mapping |
| * for an SQL user-defined type. |
| */ |
| private final static int MapTag = 8; |
| |
| /** |
| * A constant representing the tag for the max-field-size property. |
| */ |
| private final static int MaxFieldSizeTag = 9; |
| |
| /** |
| * A constant representing the tag for the max-rows property. |
| */ |
| private final static int MaxRowsTag = 10; |
| |
| /** |
| * A constant representing the tag for the query-timeout property. |
| */ |
| private final static int QueryTimeoutTag = 11; |
| |
| /** |
| * A constant representing the tag for the read-only property. |
| */ |
| private final static int ReadOnlyTag = 12; |
| |
| /** |
| * A constant representing the tag for the rowset-type property. |
| */ |
| private final static int RowsetTypeTag = 13; |
| |
| /** |
| * A constant representing the tag for the show-deleted property. |
| */ |
| private final static int ShowDeletedTag = 14; |
| |
| /** |
| * A constant representing the tag for the table-name property. |
| */ |
| private final static int TableNameTag = 15; |
| |
| /** |
| * A constant representing the tag for the URL property. |
| */ |
| private final static int UrlTag = 16; |
| |
| /** |
| * A constant representing the tag for the null property. |
| */ |
| private final static int PropNullTag = 17; |
| |
| /** |
| * A constant representing the tag for the column property. |
| */ |
| private final static int PropColumnTag = 18; |
| |
| /** |
| * A constant representing the tag for the type property. |
| */ |
| private final static int PropTypeTag = 19; |
| |
| /** |
| * A constant representing the tag for the class property. |
| */ |
| private final static int PropClassTag = 20; |
| |
| /** |
| * A constant representing the tag for the sync-provider. |
| */ |
| private final static int SyncProviderTag = 21; |
| |
| /** |
| * A constant representing the tag for the sync-provider |
| * name |
| */ |
| private final static int SyncProviderNameTag = 22; |
| |
| /** |
| * A constant representing the tag for the sync-provider |
| * vendor tag. |
| */ |
| private final static int SyncProviderVendorTag = 23; |
| |
| /** |
| * A constant representing the tag for the sync-provider |
| * version tag. |
| */ |
| private final static int SyncProviderVersionTag = 24; |
| |
| /** |
| * A constant representing the tag for the sync-provider |
| * grade tag. |
| */ |
| private final static int SyncProviderGradeTag = 25; |
| |
| /** |
| * A constant representing the tag for the data source lock. |
| */ |
| private final static int DataSourceLock = 26; |
| |
| /** |
| * A listing of the kinds of metadata information available about |
| * the columns in a <code>WebRowSet</code> object. |
| */ |
| private String [] colDef = {"column-count", "column-definition", "column-index", |
| "auto-increment", "case-sensitive", "currency", |
| "nullable", "signed", "searchable", |
| "column-display-size", "column-label", "column-name", |
| "schema-name", "column-precision", "column-scale", |
| "table-name", "catalog-name", "column-type", |
| "column-type-name", "null"}; |
| |
| |
| /** |
| * A constant representing the tag for column-count. |
| */ |
| private final static int ColumnCountTag = 0; |
| |
| /** |
| * A constant representing the tag for column-definition. |
| */ |
| private final static int ColumnDefinitionTag = 1; |
| |
| /** |
| * A constant representing the tag for column-index. |
| */ |
| private final static int ColumnIndexTag = 2; |
| |
| /** |
| * A constant representing the tag for auto-increment. |
| */ |
| private final static int AutoIncrementTag = 3; |
| |
| /** |
| * A constant representing the tag for case-sensitive. |
| */ |
| private final static int CaseSensitiveTag = 4; |
| |
| /** |
| * A constant representing the tag for currency. |
| */ |
| private final static int CurrencyTag = 5; |
| |
| /** |
| * A constant representing the tag for nullable. |
| */ |
| private final static int NullableTag = 6; |
| |
| /** |
| * A constant representing the tag for signed. |
| */ |
| private final static int SignedTag = 7; |
| |
| /** |
| * A constant representing the tag for searchable. |
| */ |
| private final static int SearchableTag = 8; |
| |
| /** |
| * A constant representing the tag for column-display-size. |
| */ |
| private final static int ColumnDisplaySizeTag = 9; |
| |
| /** |
| * A constant representing the tag for column-label. |
| */ |
| private final static int ColumnLabelTag = 10; |
| |
| /** |
| * A constant representing the tag for column-name. |
| */ |
| private final static int ColumnNameTag = 11; |
| |
| /** |
| * A constant representing the tag for schema-name. |
| */ |
| private final static int SchemaNameTag = 12; |
| |
| /** |
| * A constant representing the tag for column-precision. |
| */ |
| private final static int ColumnPrecisionTag = 13; |
| |
| /** |
| * A constant representing the tag for column-scale. |
| */ |
| private final static int ColumnScaleTag = 14; |
| |
| /** |
| * A constant representing the tag for table-name. |
| */ |
| private final static int MetaTableNameTag = 15; |
| |
| /** |
| * A constant representing the tag for catalog-name. |
| */ |
| private final static int CatalogNameTag = 16; |
| |
| /** |
| * A constant representing the tag for column-type. |
| */ |
| private final static int ColumnTypeTag = 17; |
| |
| /** |
| * A constant representing the tag for column-type-name. |
| */ |
| private final static int ColumnTypeNameTag = 18; |
| |
| /** |
| * A constant representing the tag for null. |
| */ |
| private final static int MetaNullTag = 19; |
| |
| private String [] data = {"currentRow", "columnValue", "insertRow", "deleteRow", "insdel", "updateRow", "null" , "emptyString"}; |
| |
| private final static int RowTag = 0; |
| private final static int ColTag = 1; |
| private final static int InsTag = 2; |
| private final static int DelTag = 3; |
| private final static int InsDelTag = 4; |
| private final static int UpdTag = 5; |
| private final static int NullTag = 6; |
| private final static int EmptyStringTag = 7; |
| |
| /** |
| * A constant indicating the state of this <code>XmlReaderContentHandler</code> |
| * object in which it has not yet been called by the SAX parser and therefore |
| * has no indication of what type of input to expect from the parser next. |
| * <P> |
| * The state is set to <code>INITIAL</code> at the end of each |
| * section, which allows the sections to appear in any order and |
| * still be parsed correctly (except that metadata must be |
| * set before data values can be set). |
| */ |
| private final static int INITIAL = 0; |
| |
| /** |
| * A constant indicating the state in which this <code>XmlReaderContentHandler</code> |
| * object expects the next input received from the |
| * SAX parser to be a string corresponding to one of the elements in |
| * <code>properties</code>. |
| */ |
| private final static int PROPERTIES = 1; |
| |
| /** |
| * A constant indicating the state in which this <code>XmlReaderContentHandler</code> |
| * object expects the next input received from the |
| * SAX parser to be a string corresponding to one of the elements in |
| * <code>colDef</code>. |
| */ |
| private final static int METADATA = 2; |
| |
| /** |
| * A constant indicating the state in which this <code>XmlReaderContentHandler</code> |
| * object expects the next input received from the |
| * SAX parser to be a string corresponding to one of the elements in |
| * <code>data</code>. |
| */ |
| private final static int DATA = 3; |
| |
| private JdbcRowSetResourceBundle resBundle; |
| |
| /** |
| * Constructs a new <code>XmlReaderContentHandler</code> object that will |
| * assist the SAX parser in reading a <code>WebRowSet</code> object in the |
| * format of an XML document. In addition to setting some default values, |
| * this constructor creates three <code>HashMap</code> objects, one for |
| * properties, one for metadata, and one for data. These hash maps map the |
| * strings sent by the SAX parser to integer constants so that they can be |
| * compared more efficiently in <code>switch</code> statements. |
| * |
| * @param r the <code>RowSet</code> object in XML format that will be read |
| */ |
| public XmlReaderContentHandler(RowSet r) { |
| // keep the rowset we've been given |
| rs = (WebRowSetImpl)r; |
| |
| // set-up the token maps |
| initMaps(); |
| |
| // allocate the collection for the updates |
| updates = new Vector(); |
| |
| // start out with the empty string |
| columnValue = ""; |
| propertyValue = ""; |
| metaDataValue = ""; |
| |
| nullVal = false; |
| idx = 0; |
| tempStr = ""; |
| tempUpdate = ""; |
| tempCommand = ""; |
| |
| try { |
| resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); |
| } catch(IOException ioe) { |
| throw new RuntimeException(ioe); |
| } |
| } |
| |
| /** |
| * Creates and initializes three new <code>HashMap</code> objects that map |
| * the strings returned by the SAX parser to <code>Integer</code> |
| * objects. The strings returned by the parser will match the strings that |
| * are array elements in this <code>XmlReaderContentHandler</code> object's |
| * <code>properties</code>, <code>colDef</code>, or <code>data</code> |
| * fields. For each array element in these fields, there is a corresponding |
| * constant defined. It is to these constants that the strings are mapped. |
| * In the <code>HashMap</code> objects, the string is the key, and the |
| * integer is the value. |
| * <P> |
| * The purpose of the mapping is to make comparisons faster. Because comparing |
| * numbers is more efficient than comparing strings, the strings returned |
| * by the parser are mapped to integers, which can then be used in a |
| * <code>switch</code> statement. |
| */ |
| private void initMaps() { |
| int items, i; |
| |
| propMap = new HashMap(); |
| items = properties.length; |
| |
| for (i=0;i<items;i++) { |
| propMap.put(properties[i], Integer.valueOf(i)); |
| } |
| |
| colDefMap = new HashMap(); |
| items = colDef.length; |
| |
| for (i=0;i<items;i++) { |
| colDefMap.put(colDef[i], Integer.valueOf(i)); |
| } |
| |
| dataMap = new HashMap(); |
| items = data.length; |
| |
| for (i=0;i<items;i++) { |
| dataMap.put(data[i], Integer.valueOf(i)); |
| } |
| |
| //Initialize connection map here |
| typeMap = new HashMap(); |
| } |
| |
| public void startDocument() throws SAXException { |
| } |
| |
| public void endDocument() throws SAXException { |
| } |
| |
| |
| /** |
| * Sets this <code>XmlReaderContentHandler</code> object's <code>tag</code> |
| * field if the given name is the key for a tag and this object's state |
| * is not <code>INITIAL</code>. The field is set |
| * to the constant that corresponds to the given element name. |
| * If the state is <code>INITIAL</code>, the state is set to the given |
| * name, which will be one of the sections <code>PROPERTIES</code>, |
| * <code>METADATA</code>, or <code>DATA</code>. In either case, this |
| * method puts this document handler in the proper state for calling |
| * the method <code>endElement</code>. |
| * <P> |
| * If the state is <code>DATA</code> and the tag is <code>RowTag</code>, |
| * <code>DelTag</code>, or <code>InsTag</code>, this method moves the |
| * rowset's cursor to the insert row and sets this |
| * <code>XmlReaderContentHandler</code> object's <code>idx</code> |
| * field to <code>0</code> so that it will be in the proper |
| * state when the parser calls the method <code>endElement</code>. |
| * |
| * @param lName the name of the element; either (1) one of the array |
| * elements in the fields <code>properties</code>, |
| * <code>colDef</code>, or <code>data</code> or |
| * (2) one of the <code>RowSet</code> elements |
| * <code>"properties"</code>, <code>"metadata"</code>, or |
| * <code>"data"</code> |
| * @param attributes <code>org.xml.sax.AttributeList</code> objects that are |
| * attributes of the named section element; may be <code>null</code> |
| * if there are no attributes, which is the case for |
| * <code>WebRowSet</code> objects |
| * @exception SAXException if a general SAX error occurs |
| */ |
| public void startElement(String uri, String lName, String qName, Attributes attributes) throws SAXException { |
| int tag; |
| String name = ""; |
| |
| name = lName; |
| |
| switch (getState()) { |
| case PROPERTIES: |
| |
| tempCommand = ""; |
| tag = ((Integer)propMap.get(name)).intValue(); |
| if (tag == PropNullTag) |
| setNullValue(true); |
| else |
| setTag(tag); |
| break; |
| case METADATA: |
| tag = ((Integer)colDefMap.get(name)).intValue(); |
| |
| if (tag == MetaNullTag) |
| setNullValue(true); |
| else |
| setTag(tag); |
| break; |
| case DATA: |
| |
| /** |
| * This has been added to clear out the values of the previous read |
| * so that we should not add up values of data between different tags |
| */ |
| tempStr = ""; |
| tempUpdate = ""; |
| if(dataMap.get(name) == null) { |
| tag = NullTag; |
| } else if(((Integer)dataMap.get(name)).intValue() == EmptyStringTag) { |
| tag = EmptyStringTag; |
| } else { |
| tag = ((Integer)dataMap.get(name)).intValue(); |
| } |
| |
| if (tag == NullTag) { |
| setNullValue(true); |
| } else if(tag == EmptyStringTag) { |
| setEmptyStringValue(true); |
| } else { |
| setTag(tag); |
| |
| if (tag == RowTag || tag == DelTag || tag == InsTag) { |
| idx = 0; |
| try { |
| rs.moveToInsertRow(); |
| } catch (SQLException ex) { |
| ; |
| } |
| } |
| } |
| |
| break; |
| default: |
| setState(name); |
| } |
| |
| } |
| |
| /** |
| * Sets the value for the given element if <code>name</code> is one of |
| * the array elements in the fields <code>properties</code>, |
| * <code>colDef</code>, or <code>data</code> and this |
| * <code>XmlReaderContentHandler</code> object's state is not |
| * <code>INITIAL</code>. If the state is <code>INITIAL</code>, |
| * this method does nothing. |
| * <P> |
| * If the state is <code>METADATA</code> and |
| * the argument supplied is <code>"metadata"</code>, the rowset's |
| * metadata is set. If the state is <code>PROPERTIES</code>, the |
| * appropriate property is set using the given name to determine |
| * the appropriate value. If the state is <code>DATA</code> and |
| * the argument supplied is <code>"data"</code>, this method sets |
| * the state to <code>INITIAL</code> and returns. If the argument |
| * supplied is one of the elements in the field <code>data</code>, |
| * this method makes the appropriate changes to the rowset's data. |
| * |
| * @param lName the name of the element; either (1) one of the array |
| * elements in the fields <code>properties</code>, |
| * <code>colDef</code>, or <code>data</code> or |
| * (2) one of the <code>RowSet</code> elements |
| * <code>"properties"</code>, <code>"metadata"</code>, or |
| * <code>"data"</code> |
| * |
| * @exception SAXException if a general SAX error occurs |
| */ |
| public void endElement(String uri, String lName, String qName) throws SAXException { |
| int tag; |
| |
| String name = ""; |
| name = lName; |
| |
| switch (getState()) { |
| case PROPERTIES: |
| if (name.equals("properties")) { |
| state = INITIAL; |
| break; |
| } |
| |
| try { |
| tag = ((Integer)propMap.get(name)).intValue(); |
| switch (tag) { |
| case KeycolsTag: |
| if (keyCols != null) { |
| int i[] = new int[keyCols.size()]; |
| for (int j = 0; j < i.length; j++) |
| i[j] = Integer.parseInt((String)keyCols.elementAt(j)); |
| rs.setKeyColumns(i); |
| } |
| break; |
| |
| case PropClassTag: |
| //Added the handling for Class tags to take care of maps |
| //Makes an entry into the map upon end of class tag |
| try{ |
| typeMap.put(Key_map,Class.forName(Value_map)); |
| |
| }catch(ClassNotFoundException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errmap").toString(), ex.getMessage())); |
| } |
| break; |
| |
| case MapTag: |
| //Added the handling for Map to take set the typeMap |
| rs.setTypeMap(typeMap); |
| break; |
| |
| default: |
| break; |
| } |
| |
| if (getNullValue()) { |
| setPropertyValue(null); |
| setNullValue(false); |
| } else { |
| setPropertyValue(propertyValue); |
| } |
| } catch (SQLException ex) { |
| throw new SAXException(ex.getMessage()); |
| } |
| |
| // propertyValue need to be reset to an empty string |
| propertyValue = ""; |
| setTag(-1); |
| break; |
| case METADATA: |
| if (name.equals("metadata")) { |
| try { |
| rs.setMetaData(md); |
| state = INITIAL; |
| } catch (SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errmetadata").toString(), ex.getMessage())); |
| } |
| } else { |
| try { |
| if (getNullValue()) { |
| setMetaDataValue(null); |
| setNullValue(false); |
| } else { |
| setMetaDataValue(metaDataValue); |
| } |
| } catch (SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errmetadata").toString(), ex.getMessage())); |
| |
| } |
| // metaDataValue needs to be reset to an empty string |
| metaDataValue = ""; |
| } |
| setTag(-1); |
| break; |
| case DATA: |
| if (name.equals("data")) { |
| state = INITIAL; |
| return; |
| } |
| |
| if(dataMap.get(name) == null) { |
| tag = NullTag; |
| } else { |
| tag = ((Integer)dataMap.get(name)).intValue(); |
| } |
| switch (tag) { |
| case ColTag: |
| try { |
| idx++; |
| if (getNullValue()) { |
| insertValue(null); |
| setNullValue(false); |
| } else { |
| insertValue(tempStr); |
| } |
| // columnValue now need to be reset to the empty string |
| columnValue = ""; |
| } catch (SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errinsertval").toString(), ex.getMessage())); |
| } |
| break; |
| case RowTag: |
| try { |
| rs.insertRow(); |
| rs.moveToCurrentRow(); |
| rs.next(); |
| |
| // Making this as the original to turn off the |
| // rowInserted flagging |
| rs.setOriginalRow(); |
| |
| applyUpdates(); |
| } catch (SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errconstr").toString(), ex.getMessage())); |
| } |
| break; |
| case DelTag: |
| try { |
| rs.insertRow(); |
| rs.moveToCurrentRow(); |
| rs.next(); |
| rs.setOriginalRow(); |
| applyUpdates(); |
| } catch (SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errdel").toString() , ex.getMessage())); |
| } |
| break; |
| case InsTag: |
| try { |
| rs.insertRow(); |
| rs.moveToCurrentRow(); |
| rs.next(); |
| applyUpdates(); |
| } catch (SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errinsert").toString() , ex.getMessage())); |
| } |
| break; |
| |
| case InsDelTag: |
| try { |
| rs.insertRow(); |
| rs.moveToCurrentRow(); |
| rs.next(); |
| rs.setOriginalRow(); |
| applyUpdates(); |
| } catch (SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errinsdel").toString() , ex.getMessage())); |
| } |
| break; |
| |
| case UpdTag: |
| try { |
| if(getNullValue()) |
| { |
| insertValue(null); |
| setNullValue(false); |
| } else if(getEmptyStringValue()) { |
| insertValue(""); |
| setEmptyStringValue(false); |
| } else { |
| updates.add(upd); |
| } |
| } catch(SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errupdate").toString() , ex.getMessage())); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| private void applyUpdates() throws SAXException { |
| // now handle any updates |
| if (updates.size() > 0) { |
| try { |
| Object upd[]; |
| Iterator i = updates.iterator(); |
| while (i.hasNext()) { |
| upd = (Object [])i.next(); |
| idx = ((Integer)upd[0]).intValue(); |
| |
| if(!(lastval.equals(upd[1]))){ |
| insertValue((String)(upd[1])); |
| } |
| } |
| |
| rs.updateRow(); |
| } catch (SQLException ex) { |
| throw new SAXException(MessageFormat.format(resBundle.handleGetObject("xmlrch.errupdrow").toString() , ex.getMessage())); |
| } |
| updates.removeAllElements(); |
| } |
| |
| |
| } |
| |
| /** |
| * Sets a property, metadata, or data value with the characters in |
| * the given array of characters, starting with the array element |
| * indicated by <code>start</code> and continuing for <code>length</code> |
| * number of characters. |
| * <P> |
| * The SAX parser invokes this method and supplies |
| * the character array, start position, and length parameter values it |
| * got from parsing the XML document. An application programmer never |
| * invokes this method directly. |
| * |
| * @param ch an array of characters supplied by the SAX parser, all or part of |
| * which will be used to set a value |
| * @param start the position in the given array at which to start |
| * @param length the number of consecutive characters to use |
| */ |
| public void characters(char[] ch, int start, int length) throws SAXException { |
| try { |
| switch (getState()) { |
| case PROPERTIES: |
| propertyValue = new String(ch, start, length); |
| |
| /** |
| * This has been added for handling of special characters. When special |
| * characters are encountered the characters function gets called for |
| * each of the characters so we need to append the value got in the |
| * previous call as it is the same data present between the start and |
| * the end tag. |
| **/ |
| tempCommand = tempCommand.concat(propertyValue); |
| propertyValue = tempCommand; |
| |
| // Added the following check for handling of type tags in maps |
| if(tag == PropTypeTag) |
| { |
| Key_map = propertyValue; |
| } |
| |
| // Added the following check for handling of class tags in maps |
| else if(tag == PropClassTag) |
| { |
| Value_map = propertyValue; |
| } |
| break; |
| |
| case METADATA: |
| |
| // The parser will come here after the endElement as there is |
| // "\n" in the after endTag is printed. This will cause a problem |
| // when the data between the tags is an empty string so adding |
| // below condition to take care of that situation. |
| |
| if (tag == -1) |
| { |
| break; |
| } |
| |
| metaDataValue = new String(ch, start, length); |
| break; |
| case DATA: |
| setDataValue(ch, start, length); |
| break; |
| default: |
| ; |
| } |
| } catch (SQLException ex) { |
| throw new SAXException(resBundle.handleGetObject("xmlrch.chars").toString() + ex.getMessage()); |
| } |
| } |
| |
| private void setState(String s) throws SAXException { |
| if (s.equals("webRowSet")) { |
| state = INITIAL; |
| } else if (s.equals("properties")) { |
| if (state != PROPERTIES) |
| state = PROPERTIES; |
| else |
| state = INITIAL; |
| } else if (s.equals("metadata")) { |
| if (state != METADATA) |
| state = METADATA; |
| else |
| state = INITIAL; |
| } else if (s.equals("data")) { |
| if (state != DATA) |
| state = DATA; |
| else |
| state = INITIAL; |
| } |
| |
| } |
| |
| /** |
| * Retrieves the current state of this <code>XmlReaderContentHandler</code> |
| * object's rowset, which is stored in the document handler's |
| * <code>state</code> field. |
| * |
| * @return one of the following constants: |
| * <code>XmlReaderContentHandler.PROPERTIES</code> |
| * <code>XmlReaderContentHandler.METADATA</code> |
| * <code>XmlReaderContentHandler.DATA</code> |
| * <code>XmlReaderContentHandler.INITIAL</code> |
| */ |
| private int getState() { |
| return state; |
| } |
| |
| private void setTag(int t) { |
| tag = t; |
| } |
| |
| private int getTag() { |
| return tag; |
| } |
| |
| private void setNullValue(boolean n) { |
| nullVal = n; |
| } |
| |
| private boolean getNullValue() { |
| return nullVal; |
| } |
| |
| private void setEmptyStringValue(boolean e) { |
| emptyStringVal = e; |
| } |
| |
| private boolean getEmptyStringValue() { |
| return emptyStringVal; |
| } |
| |
| private String getStringValue(String s) { |
| return s; |
| } |
| |
| private int getIntegerValue(String s) { |
| return Integer.parseInt(s); |
| } |
| |
| private boolean getBooleanValue(String s) { |
| |
| return Boolean.valueOf(s).booleanValue(); |
| } |
| |
| private java.math.BigDecimal getBigDecimalValue(String s) { |
| return new java.math.BigDecimal(s); |
| } |
| |
| private byte getByteValue(String s) { |
| return Byte.parseByte(s); |
| } |
| |
| private short getShortValue(String s) { |
| return Short.parseShort(s); |
| } |
| |
| private long getLongValue(String s) { |
| return Long.parseLong(s); |
| } |
| |
| private float getFloatValue(String s) { |
| return Float.parseFloat(s); |
| } |
| |
| private double getDoubleValue(String s) { |
| return Double.parseDouble(s); |
| } |
| |
| private byte[] getBinaryValue(String s) { |
| return s.getBytes(); |
| } |
| |
| private java.sql.Date getDateValue(String s) { |
| return new java.sql.Date(getLongValue(s)); |
| } |
| |
| private java.sql.Time getTimeValue(String s) { |
| return new java.sql.Time(getLongValue(s)); |
| } |
| |
| private java.sql.Timestamp getTimestampValue(String s) { |
| return new java.sql.Timestamp(getLongValue(s)); |
| } |
| |
| private void setPropertyValue(String s) throws SQLException { |
| // find out if we are going to be dealing with a null |
| boolean nullValue = getNullValue(); |
| |
| switch(getTag()) { |
| case CommandTag: |
| if (nullValue) |
| ; //rs.setCommand(null); |
| else |
| rs.setCommand(s); |
| break; |
| case ConcurrencyTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setConcurrency(getIntegerValue(s)); |
| break; |
| case DatasourceTag: |
| if (nullValue) |
| rs.setDataSourceName(null); |
| else |
| rs.setDataSourceName(s); |
| break; |
| case EscapeProcessingTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setEscapeProcessing(getBooleanValue(s)); |
| break; |
| case FetchDirectionTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setFetchDirection(getIntegerValue(s)); |
| break; |
| case FetchSizeTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setFetchSize(getIntegerValue(s)); |
| break; |
| case IsolationLevelTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setTransactionIsolation(getIntegerValue(s)); |
| break; |
| case KeycolsTag: |
| break; |
| case PropColumnTag: |
| if (keyCols == null) |
| keyCols = new Vector(); |
| keyCols.add(s); |
| break; |
| case MapTag: |
| break; |
| case MaxFieldSizeTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setMaxFieldSize(getIntegerValue(s)); |
| break; |
| case MaxRowsTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setMaxRows(getIntegerValue(s)); |
| break; |
| case QueryTimeoutTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setQueryTimeout(getIntegerValue(s)); |
| break; |
| case ReadOnlyTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setReadOnly(getBooleanValue(s)); |
| break; |
| case RowsetTypeTag: |
| if (nullValue) { |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| } else { |
| //rs.setType(getIntegerValue(s)); |
| String strType = getStringValue(s); |
| int iType = 0; |
| |
| if(strType.trim().equals("ResultSet.TYPE_SCROLL_INSENSITIVE")) { |
| iType = 1004; |
| } else if(strType.trim().equals("ResultSet.TYPE_SCROLL_SENSITIVE")) { |
| iType = 1005; |
| } else if(strType.trim().equals("ResultSet.TYPE_FORWARD_ONLY")) { |
| iType = 1003; |
| } |
| rs.setType(iType); |
| } |
| break; |
| case ShowDeletedTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue").toString()); |
| else |
| rs.setShowDeleted(getBooleanValue(s)); |
| break; |
| case TableNameTag: |
| if (nullValue) |
| //rs.setTableName(null); |
| ; |
| else |
| rs.setTableName(s); |
| break; |
| case UrlTag: |
| if (nullValue) |
| rs.setUrl(null); |
| else |
| rs.setUrl(s); |
| break; |
| case SyncProviderNameTag: |
| if (nullValue) { |
| rs.setSyncProvider(null); |
| } else { |
| String str = s.substring(0,s.indexOf("@")+1); |
| rs.setSyncProvider(str); |
| } |
| break; |
| case SyncProviderVendorTag: |
| // to be implemented |
| break; |
| case SyncProviderVersionTag: |
| // to be implemented |
| break; |
| case SyncProviderGradeTag: |
| // to be implemented |
| break; |
| case DataSourceLock: |
| // to be implemented |
| break; |
| default: |
| break; |
| } |
| |
| } |
| |
| private void setMetaDataValue(String s) throws SQLException { |
| // find out if we are going to be dealing with a null |
| boolean nullValue = getNullValue(); |
| |
| switch (getTag()) { |
| case ColumnCountTag: |
| md = new RowSetMetaDataImpl(); |
| idx = 0; |
| |
| if (nullValue) { |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| } else { |
| md.setColumnCount(getIntegerValue(s)); |
| } |
| break; |
| case ColumnDefinitionTag: |
| break; |
| case ColumnIndexTag: |
| idx++; |
| break; |
| case AutoIncrementTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setAutoIncrement(idx, getBooleanValue(s)); |
| break; |
| case CaseSensitiveTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setCaseSensitive(idx, getBooleanValue(s)); |
| break; |
| case CurrencyTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setCurrency(idx, getBooleanValue(s)); |
| break; |
| case NullableTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setNullable(idx, getIntegerValue(s)); |
| break; |
| case SignedTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setSigned(idx, getBooleanValue(s)); |
| break; |
| case SearchableTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setSearchable(idx, getBooleanValue(s)); |
| break; |
| case ColumnDisplaySizeTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setColumnDisplaySize(idx, getIntegerValue(s)); |
| break; |
| case ColumnLabelTag: |
| if (nullValue) |
| md.setColumnLabel(idx, null); |
| else |
| md.setColumnLabel(idx, s); |
| break; |
| case ColumnNameTag: |
| if (nullValue) |
| md.setColumnName(idx, null); |
| else |
| md.setColumnName(idx, s); |
| |
| break; |
| case SchemaNameTag: |
| if (nullValue) { |
| md.setSchemaName(idx, null); } |
| else |
| md.setSchemaName(idx, s); |
| break; |
| case ColumnPrecisionTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setPrecision(idx, getIntegerValue(s)); |
| break; |
| case ColumnScaleTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setScale(idx, getIntegerValue(s)); |
| break; |
| case MetaTableNameTag: |
| if (nullValue) |
| md.setTableName(idx, null); |
| else |
| md.setTableName(idx, s); |
| break; |
| case CatalogNameTag: |
| if (nullValue) |
| md.setCatalogName(idx, null); |
| else |
| md.setCatalogName(idx, s); |
| break; |
| case ColumnTypeTag: |
| if (nullValue) |
| throw new SQLException(resBundle.handleGetObject("xmlrch.badvalue1").toString()); |
| else |
| md.setColumnType(idx, getIntegerValue(s)); |
| break; |
| case ColumnTypeNameTag: |
| if (nullValue) |
| md.setColumnTypeName(idx, null); |
| else |
| md.setColumnTypeName(idx, s); |
| break; |
| default: |
| //System.out.println("MetaData: Unknown Tag: (" + getTag() + ")"); |
| break; |
| |
| } |
| } |
| |
| private void setDataValue(char[] ch, int start, int len) throws SQLException { |
| switch (getTag()) { |
| case ColTag: |
| columnValue = new String(ch, start, len); |
| /** |
| * This has been added for handling of special characters. When special |
| * characters are encountered the characters function gets called for |
| * each of the characters so we need to append the value got in the |
| * previous call as it is the same data present between the start and |
| * the end tag. |
| **/ |
| tempStr = tempStr.concat(columnValue); |
| break; |
| case UpdTag: |
| upd = new Object[2]; |
| |
| /** |
| * This has been added for handling of special characters. When special |
| * characters are encountered the characters function gets called for |
| * each of the characters so we need to append the value got in the |
| * previous call as it is the same data present between the start and |
| * the end tag. |
| **/ |
| |
| tempUpdate = tempUpdate.concat(new String(ch,start,len)); |
| upd[0] = Integer.valueOf(idx); |
| upd[1] = tempUpdate; |
| //updates.add(upd); |
| |
| lastval = (String)upd[1]; |
| //insertValue(ch, start, len); |
| break; |
| case InsTag: |
| |
| } |
| } |
| |
| private void insertValue(String s) throws SQLException { |
| |
| if (getNullValue()) { |
| rs.updateNull(idx); |
| return; |
| } |
| |
| // no longer have to deal with those pesky nulls. |
| int type = rs.getMetaData().getColumnType(idx); |
| switch (type) { |
| case java.sql.Types.BIT: |
| rs.updateBoolean(idx, getBooleanValue(s)); |
| break; |
| case java.sql.Types.BOOLEAN: |
| rs.updateBoolean(idx, getBooleanValue(s)); |
| break; |
| case java.sql.Types.SMALLINT: |
| case java.sql.Types.TINYINT: |
| rs.updateShort(idx, getShortValue(s)); |
| break; |
| case java.sql.Types.INTEGER: |
| rs.updateInt(idx, getIntegerValue(s)); |
| break; |
| case java.sql.Types.BIGINT: |
| rs.updateLong(idx, getLongValue(s)); |
| break; |
| case java.sql.Types.REAL: |
| case java.sql.Types.FLOAT: |
| rs.updateFloat(idx, getFloatValue(s)); |
| break; |
| case java.sql.Types.DOUBLE: |
| rs.updateDouble(idx, getDoubleValue(s)); |
| break; |
| case java.sql.Types.NUMERIC: |
| case java.sql.Types.DECIMAL: |
| rs.updateObject(idx, getBigDecimalValue(s)); |
| break; |
| case java.sql.Types.BINARY: |
| case java.sql.Types.VARBINARY: |
| case java.sql.Types.LONGVARBINARY: |
| rs.updateBytes(idx, getBinaryValue(s)); |
| break; |
| case java.sql.Types.DATE: |
| rs.updateDate(idx, getDateValue(s)); |
| break; |
| case java.sql.Types.TIME: |
| rs.updateTime(idx, getTimeValue(s)); |
| break; |
| case java.sql.Types.TIMESTAMP: |
| rs.updateTimestamp(idx, getTimestampValue(s)); |
| break; |
| case java.sql.Types.CHAR: |
| case java.sql.Types.VARCHAR: |
| case java.sql.Types.LONGVARCHAR: |
| rs.updateString(idx, getStringValue(s)); |
| break; |
| default: |
| |
| } |
| |
| } |
| |
| /** |
| * Throws the given <code>SAXParseException</code> object. This |
| * exception was originally thrown by the SAX parser and is passed |
| * to the method <code>error</code> when the SAX parser invokes it. |
| * |
| * @param e the <code>SAXParseException</code> object to throw |
| */ |
| public void error (SAXParseException e) throws SAXParseException { |
| throw e; |
| } |
| |
| // dump warnings too |
| /** |
| * Prints a warning message to <code>System.out</code> giving the line |
| * number and uri for what caused the warning plus a message explaining |
| * the reason for the warning. This method is invoked by the SAX parser. |
| * |
| * @param err a warning generated by the SAX parser |
| */ |
| public void warning (SAXParseException err) throws SAXParseException { |
| System.out.println (MessageFormat.format(resBundle.handleGetObject("xmlrch.warning").toString(), new Object[] { err.getMessage(), err.getLineNumber(), err.getSystemId() })); |
| } |
| |
| /** |
| * |
| */ |
| public void notationDecl(String name, String publicId, String systemId) { |
| |
| } |
| |
| /** |
| * |
| */ |
| public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) { |
| |
| } |
| |
| /** |
| * Returns the current row of this <code>Rowset</code>object. |
| * The ResultSet's cursor is positioned at the Row which is needed |
| * |
| * @return the <code>Row</code> object on which the <code>RowSet</code> |
| * implementation objects's cursor is positioned |
| */ |
| private Row getPresentRow(WebRowSetImpl rs) throws SQLException { |
| //rs.setOriginalRow(); |
| // ResultSetMetaData rsmd = rs.getMetaData(); |
| // int numCols = rsmd.getColumnCount(); |
| // Object vals[] = new Object[numCols]; |
| // for(int j = 1; j<= numCols ; j++){ |
| // vals[j-1] = rs.getObject(j); |
| // } |
| // return(new Row(numCols, vals)); |
| return null; |
| } |
| |
| |
| |
| |
| } |