Path: blob/master/src/java.sql.rowset/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java
40948 views
/*1* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.rowset.internal;2627import com.sun.rowset.JdbcRowSetResourceBundle;28import java.sql.*;29import javax.sql.*;30import java.io.*;31import java.text.MessageFormat;32import java.util.*;3334import javax.sql.rowset.*;35import javax.sql.rowset.spi.*;3637/**38* An implementation of the {@code XmlWriter} interface, which writes a39* {@code WebRowSet} object to an output stream as an XML document.40*/4142public class WebRowSetXmlWriter implements XmlWriter, Serializable {4344/**45* The {@code java.io.Writer} object to which this {@code WebRowSetXmlWriter}46* object will write when its {@code writeXML} method is called. The value47* for this field is set with the {@code java.io.Writer} object given48* as the second argument to the {@code writeXML} method.49*/50private transient java.io.Writer writer;5152/**53* The {@code java.util.Stack} object that this {@code WebRowSetXmlWriter}54* object will use for storing the tags to be used for writing the calling55* {@code WebRowSet} object as an XML document.56*/57private java.util.Stack<String> stack;5859private JdbcRowSetResourceBundle resBundle;6061public WebRowSetXmlWriter() {6263try {64resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();65} catch(IOException ioe) {66throw new RuntimeException(ioe);67}68}6970/**71* Writes the given {@code WebRowSet} object as an XML document72* using the given {@code java.io.Writer} object. The XML document73* will include the {@code WebRowSet} object's data, metadata, and74* properties. If a data value has been updated, that information is also75* included.76* <P>77* This method is called by the {@code XmlWriter} object that is78* referenced in the calling {@code WebRowSet} object's79* {@code xmlWriter} field. The {@code XmlWriter.writeXML}80* method passes to this method the arguments that were supplied to it.81*82* @param caller the {@code WebRowSet} object to be written; must83* be a rowset for which this {@code WebRowSetXmlWriter} object84* is the writer85* @param wrt the {@code java.io.Writer} object to which86* {@code caller} will be written87* @exception SQLException if a database access error occurs or88* this {@code WebRowSetXmlWriter} object is not the writer89* for the given rowset90* @see XmlWriter#writeXML91*/92public void writeXML(WebRowSet caller, java.io.Writer wrt)93throws SQLException {9495// create a new stack for tag checking.96stack = new java.util.Stack<>();97writer = wrt;98writeRowSet(caller);99}100101/**102* Writes the given {@code WebRowSet} object as an XML document103* using the given {@code java.io.OutputStream} object. The XML document104* will include the {@code WebRowSet} object's data, metadata, and105* properties. If a data value has been updated, that information is also106* included.107* <P>108* Using stream is a faster way than using {@code java.io.Writer}109*110* This method is called by the {@code XmlWriter} object that is111* referenced in the calling {@code WebRowSet} object's112* {@code xmlWriter} field. The {@code XmlWriter.writeXML}113* method passes to this method the arguments that were supplied to it.114*115* @param caller the {@code WebRowSet} object to be written; must116* be a rowset for which this {@code WebRowSetXmlWriter} object117* is the writer118* @param oStream the {@code java.io.OutputStream} object to which119* {@code caller} will be written120* @throws SQLException if a database access error occurs or121* this {@code WebRowSetXmlWriter} object is not the writer122* for the given rowset123* @see XmlWriter#writeXML124*/125public void writeXML(WebRowSet caller, java.io.OutputStream oStream)126throws SQLException {127128// create a new stack for tag checking.129stack = new java.util.Stack<>();130writer = new OutputStreamWriter(oStream);131writeRowSet(caller);132}133134/**135*136*137* @exception SQLException if a database access error occurs138*/139private void writeRowSet(WebRowSet caller) throws SQLException {140141try {142143startHeader();144145writeProperties(caller);146writeMetaData(caller);147writeData(caller);148149endHeader();150151} catch (java.io.IOException ex) {152throw new SQLException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.ioex").toString(), ex.getMessage()));153}154}155156private void startHeader() throws java.io.IOException {157158setTag("webRowSet");159writer.write("<?xml version=\"1.0\"?>\n");160writer.write("<webRowSet xmlns=\"http://java.sun.com/xml/ns/jdbc\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");161writer.write("xsi:schemaLocation=\"http://java.sun.com/xml/ns/jdbc http://java.sun.com/xml/ns/jdbc/webrowset.xsd\">\n");162}163164private void endHeader() throws java.io.IOException {165endTag("webRowSet");166}167168/**169*170*171* @exception SQLException if a database access error occurs172*/173private void writeProperties(WebRowSet caller) throws java.io.IOException {174175beginSection("properties");176177try {178propString("command", processSpecialCharacters(caller.getCommand()));179propInteger("concurrency", caller.getConcurrency());180propString("datasource", caller.getDataSourceName());181propBoolean("escape-processing",182caller.getEscapeProcessing());183184try {185propInteger("fetch-direction", caller.getFetchDirection());186} catch(SQLException sqle) {187// it may be the case that fetch direction has not been set188// fetchDir == 0189// in that case it will throw a SQLException.190// To avoid that catch it here191}192193propInteger("fetch-size", caller.getFetchSize());194propInteger("isolation-level",195caller.getTransactionIsolation());196197beginSection("key-columns");198199int[] kc = caller.getKeyColumns();200for (int i = 0; kc != null && i < kc.length; i++)201propInteger("column", kc[i]);202203endSection("key-columns");204205//Changed to beginSection and endSection for maps for proper indentation206beginSection("map");207Map<String, Class<?>> typeMap = caller.getTypeMap();208if(typeMap != null) {209for(Map.Entry<String, Class<?>> mm : typeMap.entrySet()) {210propString("type", mm.getKey());211propString("class", mm.getValue().getName());212}213}214endSection("map");215216propInteger("max-field-size", caller.getMaxFieldSize());217propInteger("max-rows", caller.getMaxRows());218propInteger("query-timeout", caller.getQueryTimeout());219propBoolean("read-only", caller.isReadOnly());220221int itype = caller.getType();222String strType = "";223224if(itype == 1003) {225strType = "ResultSet.TYPE_FORWARD_ONLY";226} else if(itype == 1004) {227strType = "ResultSet.TYPE_SCROLL_INSENSITIVE";228} else if(itype == 1005) {229strType = "ResultSet.TYPE_SCROLL_SENSITIVE";230}231232propString("rowset-type", strType);233234propBoolean("show-deleted", caller.getShowDeleted());235propString("table-name", caller.getTableName());236propString("url", caller.getUrl());237238beginSection("sync-provider");239// Remove the string after "@xxxx"240// before writing it to the xml file.241String strProviderInstance = (caller.getSyncProvider()).toString();242String strProvider = strProviderInstance.substring(0, (caller.getSyncProvider()).toString().indexOf('@'));243244propString("sync-provider-name", strProvider);245propString("sync-provider-vendor", "Oracle Corporation");246propString("sync-provider-version", "1.0");247propInteger("sync-provider-grade", caller.getSyncProvider().getProviderGrade());248propInteger("data-source-lock", caller.getSyncProvider().getDataSourceLock());249250endSection("sync-provider");251252} catch (SQLException ex) {253throw new java.io.IOException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.sqlex").toString(), ex.getMessage()));254}255256endSection("properties");257}258259/**260*261*262* @exception SQLException if a database access error occurs263*/264private void writeMetaData(WebRowSet caller) throws java.io.IOException {265int columnCount;266267beginSection("metadata");268269try {270271ResultSetMetaData rsmd = caller.getMetaData();272columnCount = rsmd.getColumnCount();273propInteger("column-count", columnCount);274275for (int colIndex = 1; colIndex <= columnCount; colIndex++) {276beginSection("column-definition");277278propInteger("column-index", colIndex);279propBoolean("auto-increment", rsmd.isAutoIncrement(colIndex));280propBoolean("case-sensitive", rsmd.isCaseSensitive(colIndex));281propBoolean("currency", rsmd.isCurrency(colIndex));282propInteger("nullable", rsmd.isNullable(colIndex));283propBoolean("signed", rsmd.isSigned(colIndex));284propBoolean("searchable", rsmd.isSearchable(colIndex));285propInteger("column-display-size",rsmd.getColumnDisplaySize(colIndex));286propString("column-label", rsmd.getColumnLabel(colIndex));287propString("column-name", rsmd.getColumnName(colIndex));288propString("schema-name", rsmd.getSchemaName(colIndex));289propInteger("column-precision", rsmd.getPrecision(colIndex));290propInteger("column-scale", rsmd.getScale(colIndex));291propString("table-name", rsmd.getTableName(colIndex));292propString("catalog-name", rsmd.getCatalogName(colIndex));293propInteger("column-type", rsmd.getColumnType(colIndex));294propString("column-type-name", rsmd.getColumnTypeName(colIndex));295296endSection("column-definition");297}298} catch (SQLException ex) {299throw new java.io.IOException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.sqlex").toString(), ex.getMessage()));300}301302endSection("metadata");303}304305/**306*307*308* @exception SQLException if a database access error occurs309*/310private void writeData(WebRowSet caller) throws java.io.IOException {311ResultSet rs;312313try {314ResultSetMetaData rsmd = caller.getMetaData();315int columnCount = rsmd.getColumnCount();316int i;317318beginSection("data");319320caller.beforeFirst();321caller.setShowDeleted(true);322while (caller.next()) {323if (caller.rowDeleted() && caller.rowInserted()) {324beginSection("modifyRow");325} else if (caller.rowDeleted()) {326beginSection("deleteRow");327} else if (caller.rowInserted()) {328beginSection("insertRow");329} else {330beginSection("currentRow");331}332333for (i = 1; i <= columnCount; i++) {334if (caller.columnUpdated(i)) {335rs = caller.getOriginalRow();336rs.next();337beginTag("columnValue");338writeValue(i, (RowSet)rs);339endTag("columnValue");340beginTag("updateRow");341writeValue(i, caller);342endTag("updateRow");343} else {344beginTag("columnValue");345writeValue(i, caller);346endTag("columnValue");347}348}349350endSection(); // this is unchecked351}352endSection("data");353} catch (SQLException ex) {354throw new java.io.IOException(MessageFormat.format(resBundle.handleGetObject("wrsxmlwriter.sqlex").toString(), ex.getMessage()));355}356}357358private void writeValue(int idx, RowSet caller) throws java.io.IOException {359try {360int type = caller.getMetaData().getColumnType(idx);361362switch (type) {363case java.sql.Types.BIT:364case java.sql.Types.BOOLEAN:365boolean b = caller.getBoolean(idx);366if (caller.wasNull())367writeNull();368else369writeBoolean(b);370break;371case java.sql.Types.TINYINT:372case java.sql.Types.SMALLINT:373short s = caller.getShort(idx);374if (caller.wasNull())375writeNull();376else377writeShort(s);378break;379case java.sql.Types.INTEGER:380int i = caller.getInt(idx);381if (caller.wasNull())382writeNull();383else384writeInteger(i);385break;386case java.sql.Types.BIGINT:387long l = caller.getLong(idx);388if (caller.wasNull())389writeNull();390else391writeLong(l);392break;393case java.sql.Types.REAL:394case java.sql.Types.FLOAT:395float f = caller.getFloat(idx);396if (caller.wasNull())397writeNull();398else399writeFloat(f);400break;401case java.sql.Types.DOUBLE:402double d = caller.getDouble(idx);403if (caller.wasNull())404writeNull();405else406writeDouble(d);407break;408case java.sql.Types.NUMERIC:409case java.sql.Types.DECIMAL:410writeBigDecimal(caller.getBigDecimal(idx));411break;412case java.sql.Types.BINARY:413case java.sql.Types.VARBINARY:414case java.sql.Types.LONGVARBINARY:415break;416case java.sql.Types.DATE:417java.sql.Date date = caller.getDate(idx);418if (caller.wasNull())419writeNull();420else421writeLong(date.getTime());422break;423case java.sql.Types.TIME:424java.sql.Time time = caller.getTime(idx);425if (caller.wasNull())426writeNull();427else428writeLong(time.getTime());429break;430case java.sql.Types.TIMESTAMP:431java.sql.Timestamp ts = caller.getTimestamp(idx);432if (caller.wasNull())433writeNull();434else435writeLong(ts.getTime());436break;437case java.sql.Types.CHAR:438case java.sql.Types.VARCHAR:439case java.sql.Types.LONGVARCHAR:440writeStringData(caller.getString(idx));441break;442default:443System.out.println(resBundle.handleGetObject("wsrxmlwriter.notproper").toString());444//Need to take care of BLOB, CLOB, Array, Ref here445}446} catch (SQLException ex) {447throw new java.io.IOException(resBundle.handleGetObject("wrsxmlwriter.failedwrite").toString()+ ex.getMessage());448}449}450451/*452* This begins a new tag with a indent453*454*/455private void beginSection(String tag) throws java.io.IOException {456// store the current tag457setTag(tag);458459writeIndent(stack.size());460461// write it out462writer.write("<" + tag + ">\n");463}464465/*466* This closes a tag started by beginTag with a indent467*468*/469private void endSection(String tag) throws java.io.IOException {470writeIndent(stack.size());471472String beginTag = getTag();473474if(beginTag.indexOf("webRowSet") != -1) {475beginTag ="webRowSet";476}477478if (tag.equals(beginTag) ) {479// get the current tag and write it out480writer.write("</" + beginTag + ">\n");481} else {482;483}484writer.flush();485}486487private void endSection() throws java.io.IOException {488writeIndent(stack.size());489490// get the current tag and write it out491String beginTag = getTag();492writer.write("</" + beginTag + ">\n");493494writer.flush();495}496497private void beginTag(String tag) throws java.io.IOException {498// store the current tag499setTag(tag);500501writeIndent(stack.size());502503// write tag out504writer.write("<" + tag + ">");505}506507private void endTag(String tag) throws java.io.IOException {508String beginTag = getTag();509if (tag.equals(beginTag)) {510// get the current tag and write it out511writer.write("</" + beginTag + ">\n");512} else {513;514}515writer.flush();516}517518private void emptyTag(String tag) throws java.io.IOException {519// write an emptyTag520writer.write("<" + tag + "/>");521}522523private void setTag(String tag) {524// add the tag to stack525stack.push(tag);526}527528private String getTag() {529return stack.pop();530}531532private void writeNull() throws java.io.IOException {533emptyTag("null");534}535536private void writeStringData(String s) throws java.io.IOException {537if (s == null) {538writeNull();539} else if (s.isEmpty()) {540writeEmptyString();541} else {542543s = processSpecialCharacters(s);544545writer.write(s);546}547}548549private void writeString(String s) throws java.io.IOException {550if (s != null) {551writer.write(s);552} else {553writeNull();554}555}556557558private void writeShort(short s) throws java.io.IOException {559writer.write(Short.toString(s));560}561562private void writeLong(long l) throws java.io.IOException {563writer.write(Long.toString(l));564}565566private void writeInteger(int i) throws java.io.IOException {567writer.write(Integer.toString(i));568}569570private void writeBoolean(boolean b) throws java.io.IOException {571writer.write(Boolean.valueOf(b).toString());572}573574private void writeFloat(float f) throws java.io.IOException {575writer.write(Float.toString(f));576}577578private void writeDouble(double d) throws java.io.IOException {579writer.write(Double.toString(d));580}581582private void writeBigDecimal(java.math.BigDecimal bd) throws java.io.IOException {583if (bd != null)584writer.write(bd.toString());585else586emptyTag("null");587}588589private void writeIndent(int tabs) throws java.io.IOException {590// indent...591for (int i = 1; i < tabs; i++) {592writer.write(" ");593}594}595596private void propString(String tag, String s) throws java.io.IOException {597beginTag(tag);598writeString(s);599endTag(tag);600}601602private void propInteger(String tag, int i) throws java.io.IOException {603beginTag(tag);604writeInteger(i);605endTag(tag);606}607608private void propBoolean(String tag, boolean b) throws java.io.IOException {609beginTag(tag);610writeBoolean(b);611endTag(tag);612}613614private void writeEmptyString() throws java.io.IOException {615emptyTag("emptyString");616}617/**618* Purely for code coverage purposes..619*/620public boolean writeData(RowSetInternal caller) {621return false;622}623624625/**626* This function has been added for the processing of special characters627* lik <,>,'," and & in the data to be serialized. These have to be taken628* of specifically or else there will be parsing error while trying to read629* the contents of the XML file.630**/631632private String processSpecialCharacters(String s) {633634if(s == null) {635return null;636}637char []charStr = s.toCharArray();638String specialStr = "";639640for(int i = 0; i < charStr.length; i++) {641if(charStr[i] == '&') {642specialStr = specialStr.concat("&");643} else if(charStr[i] == '<') {644specialStr = specialStr.concat("<");645} else if(charStr[i] == '>') {646specialStr = specialStr.concat(">");647} else if(charStr[i] == '\'') {648specialStr = specialStr.concat("'");649} else if(charStr[i] == '\"') {650specialStr = specialStr.concat(""");651} else {652specialStr = specialStr.concat(String.valueOf(charStr[i]));653}654}655656s = specialStr;657return s;658}659660661/**662* This method re populates the resBundle663* during the deserialization process664*665*/666private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {667// Default state initialization happens here668ois.defaultReadObject();669// Initialization of transient Res Bundle happens here .670try {671resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();672} catch(IOException ioe) {673throw new RuntimeException(ioe);674}675676}677678static final long serialVersionUID = 7163134986189677641L;679}680681682