diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,666 @@ +/* + * Copyright 2003-2006 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.rowset.internal; + +import com.sun.rowset.JdbcRowSetResourceBundle; +import java.sql.*; +import javax.sql.*; +import java.io.*; +import java.text.MessageFormat; +import java.util.*; + +import javax.sql.rowset.*; +import javax.sql.rowset.spi.*; + +/** + * An implementation of the XmlWriter interface, which writes a + * WebRowSet object to an output stream as an XML document. + */ + +public class WebRowSetXmlWriter implements XmlWriter, Serializable { + + /** + * The java.io.Writer object to which this WebRowSetXmlWriter + * object will write when its writeXML method is called. The value + * for this field is set with the java.io.Writer object given + * as the second argument to the writeXML method. + */ + private java.io.Writer writer; + + /** + * The java.util.Stack object that this WebRowSetXmlWriter + * object will use for storing the tags to be used for writing the calling + * WebRowSet object as an XML document. + */ + private java.util.Stack stack; + + private JdbcRowSetResourceBundle resBundle; + + public WebRowSetXmlWriter() { + + try { + resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle(); + } catch(IOException ioe) { + throw new RuntimeException(ioe); + } + } + + /** + * Writes the given WebRowSet object as an XML document + * using the given java.io.Writer object. The XML document + * will include the WebRowSet object's data, metadata, and + * properties. If a data value has been updated, that information is also + * included. + *

+ * This method is called by the XmlWriter object that is + * referenced in the calling WebRowSet object's + * xmlWriter field. The XmlWriter.writeXML + * method passes to this method the arguments that were supplied to it. + * + * @param caller the WebRowSet object to be written; must + * be a rowset for which this WebRowSetXmlWriter object + * is the writer + * @param wrt the java.io.Writer object to which + * caller will be written + * @exception SQLException if a database access error occurs or + * this WebRowSetXmlWriter object is not the writer + * for the given rowset + * @see XmlWriter#writeXML + */ + public void writeXML(WebRowSet caller, java.io.Writer wrt) + throws SQLException { + + // create a new stack for tag checking. + stack = new java.util.Stack(); + writer = wrt; + writeRowSet(caller); + } + + /** + * Writes the given WebRowSet object as an XML document + * using the given java.io.OutputStream object. The XML document + * will include the WebRowSet object's data, metadata, and + * properties. If a data value has been updated, that information is also + * included. + *

+ * Using stream is a faster way than using java.io.Writer + * + * This method is called by the XmlWriter object that is + * referenced in the calling WebRowSet object's + * xmlWriter field. The XmlWriter.writeXML + * method passes to this method the arguments that were supplied to it. + * + * @param caller the WebRowSet object to be written; must + * be a rowset for which this WebRowSetXmlWriter object + * is the writer + * @param oStream the java.io.OutputStream object to which + * caller will be written + * @throws SQLException if a database access error occurs or + * this WebRowSetXmlWriter object is not the writer + * for the given rowset + * @see XmlWriter#writeXML + */ + public void writeXML(WebRowSet caller, java.io.OutputStream oStream) + throws SQLException { + + // create a new stack for tag checking. + stack = new java.util.Stack(); + writer = new OutputStreamWriter(oStream); + writeRowSet(caller); + } + + /** + * + * + * @exception SQLException if a database access error occurs + */ + private void writeRowSet(WebRowSet caller) throws SQLException { + + try { + + startHeader(); + + writeProperties(caller); + writeMetaData(caller); + writeData(caller); + + endHeader(); + + } catch (java.io.IOException ex) { + throw new SQLException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.ioex").toString(), ex.getMessage())); + } + } + + private void startHeader() throws java.io.IOException { + + setTag("webRowSet"); + writer.write("\n"); + writer.write("\n"); + } + + private void endHeader() throws java.io.IOException { + endTag("webRowSet"); + } + + /** + * + * + * @exception SQLException if a database access error occurs + */ + private void writeProperties(WebRowSet caller) throws java.io.IOException { + + beginSection("properties"); + + try { + propString("command", processSpecialCharacters(caller.getCommand())); + propInteger("concurrency", caller.getConcurrency()); + propString("datasource", caller.getDataSourceName()); + propBoolean("escape-processing", + caller.getEscapeProcessing()); + + try { + propInteger("fetch-direction", caller.getFetchDirection()); + } catch(SQLException sqle) { + // it may be the case that fetch direction has not been set + // fetchDir == 0 + // in that case it will throw a SQLException. + // To avoid that catch it here + } + + propInteger("fetch-size", caller.getFetchSize()); + propInteger("isolation-level", + caller.getTransactionIsolation()); + + beginSection("key-columns"); + + int[] kc = caller.getKeyColumns(); + for (int i = 0; kc != null && i < kc.length; i++) + propInteger("column", kc[i]); + + endSection("key-columns"); + + //Changed to beginSection and endSection for maps for proper indentation + beginSection("map"); + java.util.Map typeMap = caller.getTypeMap(); + if (typeMap != null) { + Iterator i = typeMap.keySet().iterator(); + Class c; + String type; + while (i.hasNext()) { + type = (String)i.next(); + c = (Class)typeMap.get(type); + propString("type", type); + propString("class", c.getName()); + } + } + endSection("map"); + + propInteger("max-field-size", caller.getMaxFieldSize()); + propInteger("max-rows", caller.getMaxRows()); + propInteger("query-timeout", caller.getQueryTimeout()); + propBoolean("read-only", caller.isReadOnly()); + + int itype = caller.getType(); + String strType = ""; + + if(itype == 1003) { + strType = "ResultSet.TYPE_FORWARD_ONLY"; + } else if(itype == 1004) { + strType = "ResultSet.TYPE_SCROLL_INSENSITIVE"; + } else if(itype == 1005) { + strType = "ResultSet.TYPE_SCROLL_SENSITIVE"; + } + + propString("rowset-type", strType); + + propBoolean("show-deleted", caller.getShowDeleted()); + propString("table-name", caller.getTableName()); + propString("url", caller.getUrl()); + + beginSection("sync-provider"); + // Remove the string after "@xxxx" + // before writing it to the xml file. + String strProviderInstance = (caller.getSyncProvider()).toString(); + String strProvider = strProviderInstance.substring(0, (caller.getSyncProvider()).toString().indexOf("@")); + + propString("sync-provider-name", strProvider); + propString("sync-provider-vendor", "Sun Microsystems Inc."); + propString("sync-provider-version", "1.0"); + propInteger("sync-provider-grade", caller.getSyncProvider().getProviderGrade()); + propInteger("data-source-lock", caller.getSyncProvider().getDataSourceLock()); + + endSection("sync-provider"); + + } catch (SQLException ex) { + throw new java.io.IOException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.sqlex").toString(), ex.getMessage())); + } + + endSection("properties"); + } + + /** + * + * + * @exception SQLException if a database access error occurs + */ + private void writeMetaData(WebRowSet caller) throws java.io.IOException { + int columnCount; + + beginSection("metadata"); + + try { + + ResultSetMetaData rsmd = caller.getMetaData(); + columnCount = rsmd.getColumnCount(); + propInteger("column-count", columnCount); + + for (int colIndex = 1; colIndex <= columnCount; colIndex++) { + beginSection("column-definition"); + + propInteger("column-index", colIndex); + propBoolean("auto-increment", rsmd.isAutoIncrement(colIndex)); + propBoolean("case-sensitive", rsmd.isCaseSensitive(colIndex)); + propBoolean("currency", rsmd.isCurrency(colIndex)); + propInteger("nullable", rsmd.isNullable(colIndex)); + propBoolean("signed", rsmd.isSigned(colIndex)); + propBoolean("searchable", rsmd.isSearchable(colIndex)); + propInteger("column-display-size",rsmd.getColumnDisplaySize(colIndex)); + propString("column-label", rsmd.getColumnLabel(colIndex)); + propString("column-name", rsmd.getColumnName(colIndex)); + propString("schema-name", rsmd.getSchemaName(colIndex)); + propInteger("column-precision", rsmd.getPrecision(colIndex)); + propInteger("column-scale", rsmd.getScale(colIndex)); + propString("table-name", rsmd.getTableName(colIndex)); + propString("catalog-name", rsmd.getCatalogName(colIndex)); + propInteger("column-type", rsmd.getColumnType(colIndex)); + propString("column-type-name", rsmd.getColumnTypeName(colIndex)); + + endSection("column-definition"); + } + } catch (SQLException ex) { + throw new java.io.IOException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.sqlex").toString(), ex.getMessage())); + } + + endSection("metadata"); + } + + /** + * + * + * @exception SQLException if a database access error occurs + */ + private void writeData(WebRowSet caller) throws java.io.IOException { + ResultSet rs; + + try { + ResultSetMetaData rsmd = caller.getMetaData(); + int columnCount = rsmd.getColumnCount(); + int i; + + beginSection("data"); + + caller.beforeFirst(); + caller.setShowDeleted(true); + while (caller.next()) { + if (caller.rowDeleted() && caller.rowInserted()) { + beginSection("modifyRow"); + } else if (caller.rowDeleted()) { + beginSection("deleteRow"); + } else if (caller.rowInserted()) { + beginSection("insertRow"); + } else { + beginSection("currentRow"); + } + + for (i = 1; i <= columnCount; i++) { + if (caller.columnUpdated(i)) { + rs = caller.getOriginalRow(); + rs.next(); + beginTag("columnValue"); + writeValue(i, (RowSet)rs); + endTag("columnValue"); + beginTag("updateRow"); + writeValue(i, caller); + endTag("updateRow"); + } else { + beginTag("columnValue"); + writeValue(i, caller); + endTag("columnValue"); + } + } + + endSection(); // this is unchecked + } + endSection("data"); + } catch (SQLException ex) { + throw new java.io.IOException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.sqlex").toString(), ex.getMessage())); + } + } + + private void writeValue(int idx, RowSet caller) throws java.io.IOException { + try { + int type = caller.getMetaData().getColumnType(idx); + + switch (type) { + case java.sql.Types.BIT: + case java.sql.Types.BOOLEAN: + boolean b = caller.getBoolean(idx); + if (caller.wasNull()) + writeNull(); + else + writeBoolean(b); + break; + case java.sql.Types.TINYINT: + case java.sql.Types.SMALLINT: + short s = caller.getShort(idx); + if (caller.wasNull()) + writeNull(); + else + writeShort(s); + break; + case java.sql.Types.INTEGER: + int i = caller.getInt(idx); + if (caller.wasNull()) + writeNull(); + else + writeInteger(caller.getInt(idx)); + break; + case java.sql.Types.BIGINT: + long l = caller.getLong(idx); + if (caller.wasNull()) + writeNull(); + else + writeLong(l); + break; + case java.sql.Types.REAL: + case java.sql.Types.FLOAT: + float f = caller.getFloat(idx); + if (caller.wasNull()) + writeNull(); + else + writeFloat(f); + break; + case java.sql.Types.DOUBLE: + double d = caller.getDouble(idx); + if (caller.wasNull()) + writeNull(); + else + writeDouble(d); + break; + case java.sql.Types.NUMERIC: + case java.sql.Types.DECIMAL: + writeBigDecimal(caller.getBigDecimal(idx)); + break; + case java.sql.Types.BINARY: + case java.sql.Types.VARBINARY: + case java.sql.Types.LONGVARBINARY: + break; + case java.sql.Types.DATE: + java.sql.Date date = caller.getDate(idx); + if (caller.wasNull()) + writeNull(); + else + writeLong(date.getTime()); + break; + case java.sql.Types.TIME: + java.sql.Time time = caller.getTime(idx); + if (caller.wasNull()) + writeNull(); + else + writeLong(time.getTime()); + break; + case java.sql.Types.TIMESTAMP: + java.sql.Timestamp ts = caller.getTimestamp(idx); + if (caller.wasNull()) + writeNull(); + else + writeLong(ts.getTime()); + break; + case java.sql.Types.CHAR: + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + writeStringData(caller.getString(idx)); + break; + default: + System.out.println(resBundle.handleGetObject("wsrxmlwriter.notproper").toString()); + //Need to take care of BLOB, CLOB, Array, Ref here + } + } catch (SQLException ex) { + throw new java.io.IOException(resBundle.handleGetObject("wrsxmlwriter.failedwrite").toString()+ ex.getMessage()); + } + } + + /* + * This begins a new tag with a indent + * + */ + private void beginSection(String tag) throws java.io.IOException { + // store the current tag + setTag(tag); + + writeIndent(stack.size()); + + // write it out + writer.write("<" + tag + ">\n"); + } + + /* + * This closes a tag started by beginTag with a indent + * + */ + private void endSection(String tag) throws java.io.IOException { + writeIndent(stack.size()); + + String beginTag = getTag(); + + if(beginTag.indexOf("webRowSet") != -1) { + beginTag ="webRowSet"; + } + + if (tag.equals(beginTag) ) { + // get the current tag and write it out + writer.write("\n"); + } else { + ; + } + writer.flush(); + } + + private void endSection() throws java.io.IOException { + writeIndent(stack.size()); + + // get the current tag and write it out + String beginTag = getTag(); + writer.write("\n"); + + writer.flush(); + } + + private void beginTag(String tag) throws java.io.IOException { + // store the current tag + setTag(tag); + + writeIndent(stack.size()); + + // write tag out + writer.write("<" + tag + ">"); + } + + private void endTag(String tag) throws java.io.IOException { + String beginTag = getTag(); + if (tag.equals(beginTag)) { + // get the current tag and write it out + writer.write("\n"); + } else { + ; + } + writer.flush(); + } + + private void emptyTag(String tag) throws java.io.IOException { + // write an emptyTag + writer.write("<" + tag + "/>"); + } + + private void setTag(String tag) { + // add the tag to stack + stack.push(tag); + } + + private String getTag() { + return (String)stack.pop(); + } + + private void writeNull() throws java.io.IOException { + emptyTag("null"); + } + + private void writeStringData(String s) throws java.io.IOException { + if (s == null) { + writeNull(); + } else if (s.equals("")) { + writeEmptyString(); + } else { + + s = processSpecialCharacters(s); + + writer.write(s); + } + } + + private void writeString(String s) throws java.io.IOException { + if (s != null) { + writer.write(s); + } else { + writeNull(); + } + } + + + private void writeShort(short s) throws java.io.IOException { + writer.write(Short.toString(s)); + } + + private void writeLong(long l) throws java.io.IOException { + writer.write(Long.toString(l)); + } + + private void writeInteger(int i) throws java.io.IOException { + writer.write(Integer.toString(i)); + } + + private void writeBoolean(boolean b) throws java.io.IOException { + writer.write(new Boolean(b).toString()); + } + + private void writeFloat(float f) throws java.io.IOException { + writer.write(Float.toString(f)); + } + + private void writeDouble(double d) throws java.io.IOException { + writer.write(Double.toString(d)); + } + + private void writeBigDecimal(java.math.BigDecimal bd) throws java.io.IOException { + if (bd != null) + writer.write(bd.toString()); + else + emptyTag("null"); + } + + private void writeIndent(int tabs) throws java.io.IOException { + // indent... + for (int i = 1; i < tabs; i++) { + writer.write(" "); + } + } + + private void propString(String tag, String s) throws java.io.IOException { + beginTag(tag); + writeString(s); + endTag(tag); + } + + private void propInteger(String tag, int i) throws java.io.IOException { + beginTag(tag); + writeInteger(i); + endTag(tag); + } + + private void propBoolean(String tag, boolean b) throws java.io.IOException { + beginTag(tag); + writeBoolean(b); + endTag(tag); + } + + private void writeEmptyString() throws java.io.IOException { + emptyTag("emptyString"); + } + /** + * Purely for code coverage purposes.. + */ + public boolean writeData(RowSetInternal caller) { + return false; + } + + + /** + * This function has been added for the processing of special characters + * lik <,>,'," and & in the data to be serialized. These have to be taken + * of specifically or else there will be parsing error while trying to read + * the contents of the XML file. + **/ + + private String processSpecialCharacters(String s) { + + if(s == null) { + return null; + } + char []charStr = s.toCharArray(); + String specialStr = new String(); + + for(int i = 0; i < charStr.length; i++) { + if(charStr[i] == '&') { + specialStr = specialStr.concat("&"); + } else if(charStr[i] == '<') { + specialStr = specialStr.concat("<"); + } else if(charStr[i] == '>') { + specialStr = specialStr.concat(">"); + } else if(charStr[i] == '\'') { + specialStr = specialStr.concat("'"); + } else if(charStr[i] == '\"') { + specialStr = specialStr.concat("""); + } else { + specialStr = specialStr.concat(String.valueOf(charStr[i])); + } + } + + s = specialStr; + return s; + } + +}