All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.SQLServerSQLXML Maven / Gradle / Ivy

There is a newer version: 12.8.1.jre11
Show newest version
//---------------------------------------------------------------------------------------------------------------------------------
// File: SQLServerSQLXML.java
//
//
// Microsoft JDBC Driver for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), 
//  to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
 
 
package com.microsoft.sqlserver.jdbc;
import java.sql.*;
import java.io.*;

import javax.xml.XMLConstants;
import javax.xml.parsers.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.sax.*;
import javax.xml.transform.*;
import org.w3c.dom.*;
import java.text.*;
import org.xml.sax.*;
import javax.xml.transform.stax.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.helpers.XMLReaderFactory;


/**
* SQLServerSQLXML represents an XML object and implements a java.sql.SQLXML.
*/

final class SQLServerSQLXML implements java.sql.SQLXML 
{
    // Connection that created this SQLXML only set when created for setting data
    private final SQLServerConnection con;
    // Contents null means this is a setter. 
    private final PLPXMLInputStream       contents;
    private final InputStreamGetterArgs getterArgs;
    private final TypeInfo                      typeInfo;

    private boolean isUsed=false;
    private boolean isFreed = false;

    static private final java.util.logging.Logger logger =
        java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerSQLXML");

    // Setter values are held in different forms depending on which setter is used only one setter can 
    // be used at one time.
    private ByteArrayOutputStreamToInputStream outputStreamValue;
    private Document docValue;
    private String      strValue;
    // End of setter values
    
    static private int baseID = 0;	// Unique id generator for each  instance (used for logging).
    final private String traceID;
    final public String toString()
    {
        return traceID;
    }
    // Returns unique id for each instance.
    private synchronized static int nextInstanceID()
    {
        baseID++;
        return baseID;
    }

    // This method is used to get the value the user has set 
    // This is used at the execution time when sending the data to the server
    // possible optimization transform DOM straight to tds
    InputStream getValue() throws SQLServerException
    {
        checkClosed();
        // the user should have called one of the setter methods, the setter methods "use" the object and write some value.
        // Note just calling one of the setters is enough.
        if (!isUsed )
            SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_noDataXML"), null, true);
        assert null == contents;
        ByteArrayInputStream o=null;
        if(null != outputStreamValue)
        {
            o = outputStreamValue.getInputStream();
            assert null == docValue;
            assert null == strValue;
        }
        else
        if (null != docValue)
        {
            assert null ==outputStreamValue;
            assert null == strValue;
            ByteArrayOutputStreamToInputStream strm = new ByteArrayOutputStreamToInputStream();
            // Need to beat a stream out of docValue
            TransformerFactory factory;
            Writer wr=null;
            try
            {
                factory = TransformerFactory.newInstance();
                factory.newTransformer().transform(new DOMSource(docValue), new StreamResult(strm));
            }
            catch (javax.xml.transform.TransformerException e) 
            {
                MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport"));
                Object[] msgArgs = {e.toString()};
                SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
            }
            o = strm.getInputStream();
            
            try {
				strm.close();
			} catch (IOException e) {
				 throw new SQLServerException(null, e.getMessage(), null, 0, true);
			}
        }
        else 
        {
            assert null ==outputStreamValue;
            assert null == docValue;
            assert null !=strValue;
            try
            {
                o = new ByteArrayInputStream(strValue.getBytes(Encoding.UNICODE.charsetName())); 
            }
            catch (UnsupportedEncodingException ex)
            {
                throw new SQLServerException(null, ex.getMessage(), null, 0, true);
            }
        }
        assert null != o;
        isFreed = true; // we have consumed the data 
        return o;
    }
    
    // To be used in the createSQLXML call
    SQLServerSQLXML(SQLServerConnection connection)
    {
        contents =null;
        traceID = " SQLServerSQLXML:"  + nextInstanceID();
        con = connection;

        if(logger.isLoggable(java.util.logging.Level.FINE))
            logger.fine(toString() + " created by (" + connection.toString() + ")");
        getterArgs = null; // make the compiler happy
        typeInfo = null;
    }

    SQLServerSQLXML(InputStream stream,  InputStreamGetterArgs getterArgs, TypeInfo typeInfo) throws SQLServerException
    {
        traceID = " SQLServerSQLXML:"  + nextInstanceID();
        contents = (PLPXMLInputStream)stream;
        this.con = null;
        this.getterArgs = getterArgs;
        this.typeInfo = typeInfo;
        if(logger.isLoggable(java.util.logging.Level.FINE))
            logger.fine(toString() + " created by (null connection)");
    }
    InputStream getStream()
    {
        return contents;
    }
    public void free() throws SQLException
    {
        if(!isFreed)
         {
             isFreed = true;
             if(null != contents)
             {
                try
                {
                    contents.close();
                }
                catch (IOException e)
                {
                    SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true);
                }
            }
        }
    }
    private void checkClosed() throws SQLServerException
    {
        if (isFreed || (null != con && con.isClosed()) )
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_isFreed"));
            SQLServerException.makeFromDriverError(con, null, form.format(new Object[] {"SQLXML"}), null, true);
        }
    }
    private void checkReadXML() throws SQLException
    {
        if (null == contents)
            SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_writeOnlyXML"), null, true);
        if(isUsed)
            SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_dataHasBeenReadXML"), null, true);
        try
        {
            contents.checkClosed();
        }
        catch (IOException e)
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_isFreed"));
            SQLServerException.makeFromDriverError(con, null, form.format(new Object[] {"SQLXML"}), null, true);
        }
    }
    void checkWriteXML() throws SQLException
    {
        if (null != contents)
            SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_readOnlyXML"), null, true);
        if(isUsed)
            SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_dataHasBeenSetXML"), null, true);

    }

    /**
    * Return an input stream to read data from this SQLXML
    * @throws SQLServerException
    * @return the input stream to that contains the SQLXML data
    */
    public InputStream getBinaryStream() throws SQLException 
    {
        checkClosed();
        checkReadXML();
        isUsed = true;
        return contents;
    }

    /**
    * Retrieves a stream that can be used to write to the SQLXML value that this SQLXML object represents
    * The user has to write the BOM for binary streams.
    * @param pos the position in the SQLXML value at which to start writing
    * @throws SQLException
    * @return OutputStream
    */
    public java.io.OutputStream setBinaryStream() throws SQLException 
    {
        checkClosed();
        checkWriteXML();
        isUsed = true;
        outputStreamValue = new ByteArrayOutputStreamToInputStream();
        return outputStreamValue;
    }
    public java.io.Writer setCharacterStream() throws SQLException 
    {
        checkClosed();
        checkWriteXML();
        isUsed = true;
        outputStreamValue = new ByteArrayOutputStreamToInputStream();
        java.io.Writer wrt=null;
        try
        {
            wrt = new OutputStreamWriter(outputStreamValue, Encoding.UNICODE.charsetName());
        }
        catch (UnsupportedEncodingException ex)
        {
            throw new SQLServerException(null, ex.getMessage(), null, 0, true);
        }
        return wrt;
    }
    public Reader getCharacterStream() throws SQLException
    {
        checkClosed();
        checkReadXML();
        isUsed = true;   
        StreamType type = StreamType.CHARACTER;
        InputStreamGetterArgs newArgs = new InputStreamGetterArgs(
                type,
                getterArgs.isAdaptive,
                getterArgs.isStreaming,
                getterArgs.logContext);
        // Skip the BOM bytes from the plpinputstream we do not need it  for the conversion
        assert null != contents;
        // Read two bytes to eat BOM
        try
        {
            contents.read();
            contents.read();
        }
        catch (IOException e)
        {
            SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true);
        }
        
        Reader rd = (Reader)DDC.convertStreamToObject(contents,  typeInfo,type.getJDBCType(),  newArgs);
        return rd;
    }

    public String getString()  throws SQLException    
    {
        checkClosed();
        checkReadXML();
        isUsed = true;
        assert null != contents;
        // Read two bytes to eat BOM
        try
        {
            contents.read();
            contents.read();
        }
        catch (IOException e)
        {
            SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true);
        }

        byte byteContents[] = contents.getBytes();
        String ret = null;
        try
        {
            ret = new String(byteContents,0, byteContents.length, Encoding.UNICODE.charsetName() );
        }
        catch (UnsupportedEncodingException ex)
        {
            throw new SQLServerException(null, ex.getMessage(), null, 0, true);
        }
        return ret;    
    }
    public void setString(String value)  throws SQLException
    {
        checkClosed();
        checkWriteXML();
        isUsed = true;
        if(null == value)
            SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, true);
        strValue = value;
    }
    // Support the following DOMSource, SAXSource, StAX and Stream. Also, null means default which is stream source
                         
    public  T   getSource(Class iface)  throws SQLException
    {
        checkClosed();
        checkReadXML();
        if(null == iface)
        {
            // The compiler does not allow setting the null iface to StreamSource.class hence
            // this cast is needed, the cast is safe.
            @SuppressWarnings("unchecked") T src = (T)getSourceInternal(StreamSource.class);
            return src;
        }
        else
            return getSourceInternal(iface);
    }
     T   getSourceInternal(Class iface)  throws SQLException
    {
        isUsed = true;
        T src =null;
        if(DOMSource.class == iface)
        {
            src = iface.cast(getDOMSource());
        }else
        if(SAXSource.class == iface)
        {
            src = iface.cast(getSAXSource());
        }
        else
        if(StAXSource.class == iface)
        {
            src = iface.cast(getStAXSource());
        }
        else
        if(StreamSource.class == iface)
        {
            src = iface.cast(new StreamSource(contents));
        }
        else
            // Do not support this type
           SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_notSupported"), null, true);
        return src;
    }
    public  T  setResult(Class resultClass) throws SQLException
    {
        checkClosed();
        checkWriteXML();
        if(null == resultClass)
        {
            // The compiler does not allow setting the null resultClass to StreamResult.class hence
            // this cast is needed, the cast is safe.
            @SuppressWarnings("unchecked") T result = (T)setResultInternal(StreamResult.class);
            return result;
        }
        else
            return setResultInternal(resultClass);
    
    }
    
     T  setResultInternal(Class resultClass) throws SQLException
    {
        isUsed = true;
        T result=null;
        if(DOMResult.class == resultClass)
        {
            result = resultClass.cast(getDOMResult());
        }
        else
        if(SAXResult.class == resultClass)
        {
            result = resultClass.cast(getSAXResult());
        }
        else
        if(StAXResult.class == resultClass)
        {
            result = resultClass.cast(getStAXResult());
        }else 
        if(StreamResult.class == resultClass)
        {
            outputStreamValue = new ByteArrayOutputStreamToInputStream();
            result = resultClass.cast(new StreamResult(outputStreamValue));
        }
         else
            SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_notSupported"), null, true);
        return result;
    }
    // Supporting functions
    private final  DOMSource getDOMSource() throws SQLException
    {
        Document document = null;
        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder;
        try 
        {
        	//Secure feature processing is false by default for IBM parser
        	//For all others, it is true by default.
        	//So, setting it explicitly for all, irrespective of the JVM.
        	//This limits the expansion of entities.
        	//The limit is implementation specific. For IBM it's 100,000
        	//whereas for oracle it is 64,000.
        	factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);        
        	builder = factory.newDocumentBuilder();
        	
        	//set an entity resolver to disable parsing of external entities
        	builder.setEntityResolver(new SQLServerEntityResolver());
            try
            {
                document = builder.parse(contents);
            }
            catch (IOException e)
            {
                MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream"));
                Object[] msgArgs = {e.toString()};
                SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), "", true);
            }
            DOMSource inputSource = new DOMSource(document);
            return inputSource;
            
        } catch (ParserConfigurationException e) 
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport"));
            Object[] msgArgs = {e.toString()};
            SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
        }
         catch (SAXException e) 
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToParseXML"));
            Object[] msgArgs = {e.toString()};
            SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);    
        }
        return null;
    }
    private final  SAXSource getSAXSource() throws SQLException
    {
        try 
        {
            InputSource src = new InputSource(contents);
            XMLReader reader = XMLReaderFactory.createXMLReader();
            SAXSource saxSource = new SAXSource(reader, src);
            return saxSource;

        }
        catch (SAXException e) 
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToParseXML"));
            Object[] msgArgs = {e.toString()};
            SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);    
        }
        return null;
    }
    private final  StAXSource getStAXSource() throws SQLException
    {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        try 
        {
            XMLStreamReader      r =      factory.createXMLStreamReader(contents);
            StAXSource result = new StAXSource(r);
            return result;

        } catch (XMLStreamException e) 
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport"));
            Object[] msgArgs = {e.toString()};
            SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
        }
        return null;
    }

    private final  StAXResult getStAXResult() throws SQLException
    {
        XMLOutputFactory factory = XMLOutputFactory.newInstance();
        outputStreamValue = new ByteArrayOutputStreamToInputStream();
        try 
        {
            XMLStreamWriter      r =      factory.createXMLStreamWriter(outputStreamValue);
            StAXResult result = new StAXResult(r);
            return result;

        } catch (XMLStreamException e) 
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport"));
            Object[] msgArgs = {e.toString()};
            SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
        }
        return null;
    }
    private final  SAXResult getSAXResult() throws SQLException
    {
        TransformerHandler handler=null;
        try
        {
            SAXTransformerFactory stf =
                (SAXTransformerFactory)TransformerFactory.newInstance();
            handler = stf.newTransformerHandler();
        }
        catch (TransformerConfigurationException e) 
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport"));
            Object[] msgArgs = {e.toString()};
            SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
        }
        catch (ClassCastException e)
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport"));
            Object[] msgArgs = {e.toString()};
            SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
        }
        outputStreamValue = new ByteArrayOutputStreamToInputStream();
        handler.setResult(new StreamResult(outputStreamValue));
        SAXResult result= new SAXResult(handler);
        return result;
    }
    private final  DOMResult getDOMResult() throws SQLException
    {
        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder;
        assert null == outputStreamValue;
        try 
        {
            builder = factory.newDocumentBuilder();
            docValue = builder.newDocument();
            DOMResult result = new DOMResult(docValue);
            return result;
            
        } catch (ParserConfigurationException e) 
        {
            MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport"));
            Object[] msgArgs = {e.toString()};
            SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
        }
        return null;
    }

 }

// We use this class to convert the byte information we have in the string to 
// an inputstream which is used when sending to the info to the server
final class  ByteArrayOutputStreamToInputStream extends ByteArrayOutputStream
    {
         ByteArrayInputStream getInputStream() throws SQLServerException
        {
            ByteArrayInputStream is = new ByteArrayInputStream(buf, 0, count);
            return is;    
        }
    }

//Resolves External entities in an XML with inline DTDs to empty string
final class SQLServerEntityResolver implements EntityResolver
{
	public InputSource resolveEntity (String publicId, String systemId)
	{
		return new InputSource(new StringReader(""));
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy