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

org.hsqldb.jdbc.JDBCSQLXML Maven / Gradle / Ivy

There is a newer version: 2.7.2
Show newest version
/* Copyright (c) 2001-2019, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


package org.hsqldb.jdbc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLXML;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stax.StAXResult;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.ClosableByteArrayOutputStream;
import org.hsqldb.lib.StringConverter;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.Node;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

/* $Id: JDBCSQLXML.java 5968 2019-04-27 12:55:27Z fredt $ */

/**
 * 
 * The mapping in the JavaTM programming language for the SQL XML type.
 * XML is a built-in type that stores an XML value
 * as a column value in a row of a database table.
 * By default drivers implement an SQLXML object as
 * a logical pointer to the XML data
 * rather than the data itself.
 * An SQLXML object is valid for the duration of the transaction in which it was created.
 * 

* The SQLXML interface provides methods for accessing the XML value * as a String, a Reader or Writer, or as a Stream. The XML value * may also be accessed through a Source or set as a Result, which * are used with XML Parser APIs such as DOM, SAX, and StAX, as * well as with XSLT transforms and XPath evaluations. *

* Methods in the interfaces ResultSet, CallableStatement, and PreparedStatement, * such as getSQLXML allow a programmer to access an XML value. * In addition, this interface has methods for updating an XML value. *

* The XML value of the SQLXML instance may be obtained as a BinaryStream using *

 *   SQLXML sqlxml = resultSet.getSQLXML(column);
 *   InputStream binaryStream = sqlxml.getBinaryStream();
 * 
* For example, to parse an XML value with a DOM parser: *
 *   DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 *   Document result = parser.parse(binaryStream);
 * 
* or to parse an XML value with a SAX parser to your handler: *
 *   SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
 *   parser.parse(binaryStream, myHandler);
 * 
* or to parse an XML value with a StAX parser: *
 *   XMLInputFactory factory = XMLInputFactory.newInstance();
 *   XMLStreamReader streamReader = factory.createXMLStreamReader(binaryStream);
 * 
*

* Because databases may use an optimized representation for the XML, * accessing the value through getSource() and * setResult() can lead to improved processing performance * without serializing to a stream representation and parsing the XML. *

* For example, to obtain a DOM Document Node: *

 *   DOMSource domSource = sqlxml.getSource(DOMSource.class);
 *   Document document = (Document) domSource.getNode();
 * 
* or to set the value to a DOM Document Node to myNode: *
 *   DOMResult domResult = sqlxml.setResult(DOMResult.class);
 *   domResult.setNode(myNode);
 * 
* or, to send SAX events to your handler: *
 *   SAXSource saxSource = sqlxml.getSource(SAXSource.class);
 *   XMLReader xmlReader = saxSource.getXMLReader();
 *   xmlReader.setContentHandler(myHandler);
 *   xmlReader.parse(saxSource.getInputSource());
 * 
* or, to set the result value from SAX events: *
 *   SAXResult saxResult = sqlxml.setResult(SAXResult.class);
 *   ContentHandler contentHandler = saxResult.getXMLReader().getContentHandler();
 *   contentHandler.startDocument();
 *   // set the XML elements and attributes into the result
 *   contentHandler.endDocument();
 * 
* or, to obtain StAX events: *
 *   StAXSource staxSource = sqlxml.getSource(StAXSource.class);
 *   XMLStreamReader streamReader = staxSource.getXMLStreamReader();
 * 
* or, to set the result value from StAX events: *
 *   StAXResult staxResult = sqlxml.getResult(StAXResult.class);
 *   XMLStreamWriter streamWriter = staxResult.getXMLStreamWriter();
 * 
* or, to perform XSLT transformations on the XML value using the XSLT in xsltFile * output to file resultFile: *
 *   File xsltFile = new File("a.xslt");
 *   File myFile = new File("result.xml");
 *   Transformer xslt = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltFile));
 *   Source source = sqlxml.getSource(null);
 *   Result result = new StreamResult(myFile);
 *   xslt.transform(source, result);
 * 
* or, to evaluate an XPath expression on the XML value: *
 *   XPath xpath = XPathFactory.newInstance().newXPath();
 *   DOMSource domSource = sqlxml.getSource(DOMSource.class);
 *   Document document = (Document) domSource.getNode();
 *   String expression = "/foo/@bar";
 *   String barValue = xpath.evaluate(expression, document);
 * 
* To set the XML value to be the result of an XSLT transform: *
 *   File sourceFile = new File("source.xml");
 *   Transformer xslt = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltFile));
 *   Source streamSource = new StreamSource(sourceFile);
 *   Result result = sqlxml.setResult(null);
 *   xslt.transform(streamSource, result);
 * 
* Any Source can be transformed to a Result using the identity transform * specified by calling newTransformer(): *
 *   Transformer identity = TransformerFactory.newInstance().newTransformer();
 *   Source source = sqlxml.getSource(null);
 *   File myFile = new File("result.xml");
 *   Result result = new StreamResult(myFile);
 *   identity.transform(source, result);
 * 
* To write the contents of a Source to standard output: *
 *   Transformer identity = TransformerFactory.newInstance().newTransformer();
 *   Source source = sqlxml.getSource(null);
 *   Result result = new StreamResult(System.out);
 *   identity.transform(source, result);
 * 
* To create a DOMSource from a DOMResult: *
 *    DOMSource domSource = new DOMSource(domResult.getNode());
 * 
*

* Incomplete or invalid XML values may cause an SQLException when * set or the exception may occur when execute() occurs. All streams * must be closed before execute() occurs or an SQLException will be thrown. *

* Reading and writing XML values to or from an SQLXML object can happen at most once. * The conceptual states of readable and not readable determine if one * of the reading APIs will return a value or throw an exception. * The conceptual states of writable and not writable determine if one * of the writing APIs will set a value or throw an exception. *

* The state moves from readable to not readable once free() or any of the * reading APIs are called: getBinaryStream(), getCharacterStream(), getSource(), and getString(). * Implementations may also change the state to not writable when this occurs. *

* The state moves from writable to not writeable once free() or any of the * writing APIs are called: setBinaryStream(), setCharacterStream(), setResult(), and setString(). * Implementations may also change the state to not readable when this occurs. *

* All methods on the SQLXML interface must be fully implemented if the * JDBC driver supports the data type. * * * *

*

HSQLDB-Specific Information:

* * Starting with HSQLDB 2.0, a rudimentary client-side SQLXML interface * implementation (this class) is supported for local use when the product is * built and run under JDK 1.6+ and the SQLXML instance is constructed as the * result of calling JDBCConnection.createSQLXML().

* * SQLXML instances retrieved in such a fashion are initially write-only, with * the lifecycle of read and write availability constrained in accordance with * the documentation of the interface methods.

* * When build and run under JDK 1.6+, it is also possible to retrieve read-only * SQLXML instances from JDBCResultSet.getSQLXML(...), given that the underlying * data can be converted to an XML Document Object Model (DOM).

* * However, at the time of this writing (2007-06-12) it is not yet possible to * store SQLXML objects directly into an HSQLDB database or to use them directly * for HSQLDB statement parameterization purposes. This is because the SQLXML * data type is not yet natively supported by the HSQLDB engine. Instead, a * JDBCSQLXML instance must first be read as a string, binary input stream, * character input stream and so on, which can then be used for such purposes.

* * Here is the current read/write availability lifecycle for JDBCSQLXML: * *

* * * * * * * * * * * * * * * * * * * * * * * * * *
* Origin * * Initially * * After 1st Write * * After 1st Read * * After 1st Free *
* org.hsqldb.jdbc.JDBCConnection.createSQLXML() * * Write-only * * Read-only * * Not readable or writable * * Not readable or writable *
* org.hsqldb.jdbc.JDBCResultSet.getSQLXML(...) * * Read-only * * N/A * * Not readable or writable * * Not readable or writable *
*
* * * @author Campbell Burnet (campbell-burnet@users dot sourceforge.net) * @see javax.xml.parsers * @see javax.xml.stream * @see javax.xml.transform * @see javax.xml.xpath * @since JDK 1.6, HSQLDB 2.0 */ public class JDBCSQLXML implements SQLXML { private static String domFeatures = "XML 3.0 Traversal +Events 2.0"; private static DOMImplementation domImplementation; private static DOMImplementationRegistry domImplementationRegistry; private static ThreadPoolExecutor executorService; private static Transformer identityTransformer; private static TransformerFactory transformerFactory; /** * Precomputed Charset to reduce octet to character sequence conversion * charset lookup overhead. */ private static final Charset utf8Charset; private static ArrayBlockingQueue workQueue; static { Charset charset = null; try { charset = Charset.forName("UTF8"); } catch (Exception e) { } utf8Charset = charset; } /** * When non-null, the SAX ContentHandler currently in use to build this * object's SQLXML value from a SAX event sequence. */ private SAX2DOMBuilder builder; /** * Whether this object is closed. When closed, no further reading * or writing is possible. */ private boolean closed; // ------------------------- Internal Implementation ----------------------- /** * This object's SQLXML value as a GZIPed byte array */ private volatile byte[] gzdata; /** * When non-null, the stream currently in use to read this object's * SQLXML value as an octet sequence. */ private InputStream inputStream; /** * When non-null, the stream currently in use to write this object's * SQLXML value from an octet sequence. */ private ClosableByteArrayOutputStream outputStream; /** * When non-null, the DOMResult currently in use to build this object's * SQLXML value. */ private DOMResult domResult; /** * This object's public id */ private String publicId; /** * Whether it is possible to read this object's SQLXML value. */ private boolean readable; /** * This object's system id */ private String systemId; /** * Whether it is possible to write this object's SQLXML value. */ private boolean writable; /** * Constructs a new, initially write-only JDBCSQLXML object.

*/ protected JDBCSQLXML() { setReadable(false); setWritable(true); } /** * Constructs a new read-only JDBCSQLXML object from the given octet * sequence.

* * @param bytes the octet sequence representing the SQLXML value * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(byte[] bytes) throws SQLException { this(bytes, null); } /** * Constructs a new read-only JDBCSQLXML object from the given character * sequence.

* * @param chars the character sequence representing the SQLXML value * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(char[] chars) throws SQLException { this(chars, 0, chars.length, null); } /** * Constructs a new JDBCSQLXML object from the given Document.

* * @param document the Document representing the SQLXML value * @throws java.sql.SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(Document document) throws SQLException { this(new DOMSource(document)); } /** * Constructs a new read-only JDBCSQLXML object from the given octet * sequence.

* * Relative URI references will be resolved against the present working * directory reported by the Java virtual machine.

* * @param inputStream an octet stream representing an SQLXML value * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(InputStream inputStream) throws SQLException { this(inputStream, null); } /** * Constructs a new read-only JDBCSQLXML object from the given character * sequence.

* * Relative URI references will be resolved against the present working * directory reported by the Java virtual machine.

* * Note:Normally, a byte stream should be used rather than a reader, * so that the XML parser can resolve character encoding specified by the * XML declaration. However, in many cases the encoding of the input stream * is already resolved, as in the case of reading XML from a StringReader. * * @param reader a character stream representing an SQLXML value * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(Reader reader) throws SQLException { this(reader, null); } /** * Constructs a new read-only JDBCSQLXML object from the given Source * object.

* * @param source a Source representing an SQLXML value * @throws SQLException if the argument does not represent a * valid SQLXML value */ public JDBCSQLXML(Source source) throws SQLException { init(source); } /** * Constructs a new read-only JDBCSQLXML object from the given character * sequence.

* * Relative URI references will be resolved against the present working * directory reported by the Java virtual machine.

* * @param string a character sequence representing an SQLXML value * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(String string) throws SQLException { this(new StreamSource(new StringReader(string))); } /** * Constructs a new read-only JDBCSQLXML object from the given octet * sequence.

* * @param bytes the octet sequence representing the SQLXML value * @param systemId must be a String that conforms to the URI syntax; * allows relative URIs to be processed. * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(byte[] bytes, String systemId) throws SQLException { this(new StreamSource(new ByteArrayInputStream(bytes), systemId)); } protected JDBCSQLXML(char[] chars, String systemId) throws SQLException { this(chars, 0, chars.length, systemId); } /** * Constructs a new read-only JDBCSQLXML object from the given octet * sequence.

* * Relative URI references will be resolved against the given systemId.

* * @param inputStream an octet stream representing an SQLXML value * @param systemId a String that conforms to the URI syntax, indicating * the URI from which the XML data is being read, so that relative URI * references can be resolved * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(InputStream inputStream, String systemId) throws SQLException { this(new StreamSource(inputStream, systemId)); } /** * Constructs a new read-only JDBCSQLXML object from the given character * sequence.

* * Relative URI references will be resolved against the given systemId.

* * Note:Normally, a byte stream should be used rather than a reader, * so that the XML parser can resolve character encoding specified by the * XML declaration. However, in many cases the encoding of the input stream * is already resolved, as in the case of reading XML from a StringReader. * * @param reader a character stream representing an SQLXML value; * @param systemId a String that conforms to the URI syntax, indicating * the URI from which the XML data is being read, so that relative URI * references can be resolved * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(Reader reader, String systemId) throws SQLException { this(new StreamSource(reader, systemId)); } /** * Constructs a new read-only JDBCSQLXML object from the given character * sequence.

* * Relative URI references will be resolved against the given systemId.

* * @param string a character sequence representing an SQLXML value * @param systemId a String that conforms to the URI syntax, indicating * the URI from which the XML data is being read, so that relative URI * references can be resolved * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(String string, String systemId) throws SQLException { this(new StreamSource(new StringReader(string), systemId)); } /** * Constructs a new read-only JDBCSQLXML object from the given gzipped octet * sequence.

* * @param bytes the gzipped octet sequence representing the SQLXML value * @param clone whether to clone the given gzipped octet sequence * @param systemId * @param publicId * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected JDBCSQLXML(byte[] bytes, boolean clone, String systemId, String publicId) throws SQLException { this.setGZipData(clone ? bytes.clone() : bytes); this.systemId = systemId; this.publicId = publicId; } protected JDBCSQLXML(char[] chars, int offset, int length, String systemId) throws SQLException { this(new StreamSource(new CharArrayReader(chars, offset, length), systemId)); } /** * This method closes this object and releases the resources that it held. * The SQL XML object becomes invalid and neither readable or writable * when this method is called. * * After free has been called, any attempt to invoke a * method other than free will result in a SQLException * being thrown. If free is called multiple times, the subsequent * calls to free are treated as a no-op. * @throws SQLException if there is an error freeing the XML value. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 */ public void free() throws SQLException { close(); } /** * Retrieves the XML value designated by this SQLXML instance as a stream. * The bytes of the input stream are interpreted according to appendix F of the XML 1.0 specification. * The behavior of this method is the same as ResultSet.getBinaryStream() * when the designated column of the ResultSet has a type java.sql.Types of SQLXML. *

* The SQL XML object becomes not readable when this method is called and * may also become not writable depending on implementation. * * @return a stream containing the XML data. * @throws SQLException if there is an error processing the XML value. * An exception is thrown if the state is not readable. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 */ public synchronized InputStream getBinaryStream() throws SQLException { checkClosed(); checkReadable(); InputStream rval = getBinaryStreamImpl(); setReadable(false); setWritable(false); return rval; } /** * Retrieves a stream that can be used to write the XML value that this SQLXML instance represents. * The stream begins at position 0. * The bytes of the stream are interpreted according to appendix F of the XML 1.0 specification * The behavior of this method is the same as ResultSet.updateBinaryStream() * when the designated column of the ResultSet has a type java.sql.Types of SQLXML. *

* The SQL XML object becomes not writeable when this method is called and * may also become not readable depending on implementation. * * @return a stream to which data can be written. * @throws SQLException if there is an error processing the XML value. * An exception is thrown if the state is not writable. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 */ public synchronized OutputStream setBinaryStream() throws SQLException { checkClosed(); checkWritable(); OutputStream rval = setBinaryStreamImpl(); setWritable(false); setReadable(true); return rval; } /** * Retrieves the XML value designated by this SQLXML instance as a java.io.Reader object. * The format of this stream is defined by org.xml.sax.InputSource, * where the characters in the stream represent the unicode code points for * XML according to section 2 and appendix B of the XML 1.0 specification. * Although an encoding declaration other than unicode may be present, * the encoding of the stream is unicode. * The behavior of this method is the same as ResultSet.getCharacterStream() * when the designated column of the ResultSet has a type java.sql.Types of SQLXML. *

* The SQL XML object becomes not readable when this method is called and * may also become not writable depending on implementation. * * @return a stream containing the XML data. * @throws SQLException if there is an error processing the XML value. * The getCause() method of the exception may provide a more detailed exception, for example, * if the stream does not contain valid characters. * An exception is thrown if the state is not readable. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 */ public synchronized Reader getCharacterStream() throws SQLException { checkClosed(); checkReadable(); Reader reader = getCharacterStreamImpl(); setReadable(false); setWritable(false); return reader; } /** * Retrieves a stream to be used to write the XML value that this SQLXML instance represents. * The format of this stream is defined by org.xml.sax.InputSource, * where the characters in the stream represent the unicode code points for * XML according to section 2 and appendix B of the XML 1.0 specification. * Although an encoding declaration other than unicode may be present, * the encoding of the stream is unicode. * The behavior of this method is the same as ResultSet.updateCharacterStream() * when the designated column of the ResultSet has a type java.sql.Types of SQLXML. *

* The SQL XML object becomes not writable when this method is called and * may also become not readable depending on implementation. * * @return a stream to which data can be written. * @throws SQLException if there is an error processing the XML value. * The getCause() method of the exception may provide a more detailed exception, for example, * if the stream does not contain valid characters. * An exception is thrown if the state is not writable. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 Build 79 */ public synchronized Writer setCharacterStream() throws SQLException { checkClosed(); checkWritable(); Writer writer = setCharacterStreamImpl(); setReadable(true); setWritable(false); return writer; } /** * Returns a string representation of the XML value designated by this SQLXML instance. * The format of this String is defined by org.xml.sax.InputSource, * where the characters in the stream represent the unicode code points for * XML according to section 2 and appendix B of the XML 1.0 specification. * Although an encoding declaration other than unicode may be present, * the encoding of the String is unicode. * The behavior of this method is the same as ResultSet.getString() * when the designated column of the ResultSet has a type java.sql.Types of SQLXML. *

* The SQL XML object becomes not readable when this method is called and * may also become not writable depending on implementation. * * @return a string representation of the XML value designated by this SQLXML instance. * @throws SQLException if there is an error processing the XML value. * The getCause() method of the exception may provide a more detailed exception, for example, * if the stream does not contain valid characters. * An exception is thrown if the state is not readable. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 */ public synchronized String getString() throws SQLException { checkClosed(); checkReadable(); String value = getStringImpl(); setReadable(false); setWritable(false); return value; } /** * Sets the XML value designated by this SQLXML instance to the given String representation. * The format of this String is defined by org.xml.sax.InputSource, * where the characters in the stream represent the unicode code points for * XML according to section 2 and appendix B of the XML 1.0 specification. * Although an encoding declaration other than unicode may be present, * the encoding of the String is unicode. * The behavior of this method is the same as ResultSet.updateString() * when the designated column of the ResultSet has a type java.sql.Types of SQLXML. *

* The SQL XML object becomes not writeable when this method is called and * may also become not readable depending on implementation. * * @param value the XML value * @throws SQLException if there is an error processing the XML value. * The getCause() method of the exception may provide a more detailed exception, for example, * if the stream does not contain valid characters. * An exception is thrown if the state is not writable. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 */ public synchronized void setString(String value) throws SQLException { if (value == null) { throw JDBCUtil.nullArgument("value"); } checkWritable(); setStringImpl(value); setReadable(true); setWritable(false); } /** * Returns a Source for reading the XML value designated by this SQLXML instance. * Sources are used as inputs to XML parsers and XSLT transformers. *

* Sources for XML parsers will have namespace processing on by default. * The systemID of the Source is implementation dependent. *

* The SQL XML object becomes not readable when this method is called and * may also become not writable depending on implementation. *

* Note that SAX is a callback architecture, so a returned * SAXSource should then be set with a content handler that will * receive the SAX events from parsing. The content handler * will receive callbacks based on the contents of the XML. *

     *   SAXSource saxSource = sqlxml.getSource(SAXSource.class);
     *   XMLReader xmlReader = saxSource.getXMLReader();
     *   xmlReader.setContentHandler(myHandler);
     *   xmlReader.parse(saxSource.getInputSource());
     * 
* * @param sourceClass The class of the source, or null. * If the class is null, a vendor specific Source implementation will be returned. * The following classes are supported at a minimum: *
     *   javax.xml.transform.dom.DOMSource - returns a DOMSource
     *   javax.xml.transform.sax.SAXSource - returns a SAXSource
     *   javax.xml.transform.stax.StAXSource - returns a StAXSource
     *   javax.xml.transform.stream.StreamSource - returns a StreamSource
     * 
* @return a Source for reading the XML value. * @throws SQLException if there is an error processing the XML value * or if this feature is not supported. * The getCause() method of the exception may provide a more detailed exception, for example, * if an XML parser exception occurs. * An exception is thrown if the state is not readable. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 Build 79 */ @SuppressWarnings("unchecked") public synchronized T getSource( Class sourceClass) throws SQLException { checkClosed(); checkReadable(); final Source source = getSourceImpl(sourceClass); setReadable(false); setWritable(false); return (T) source; } /** * Returns a Result for setting the XML value designated by this SQLXML instance. *

* The systemID of the Result is implementation dependent. *

* The SQL XML object becomes not writable when this method is called and * may also become not readable depending on implementation. *

* Note that SAX is a callback architecture and the returned * SAXResult has a content handler assigned that will receive the * SAX events based on the contents of the XML. Call the content * handler with the contents of the XML document to assign the values. *

     *   SAXResult saxResult = sqlxml.getResult(SAXResult.class);
     *   ContentHandler contentHandler = saxResult.getXMLReader().getContentHandler();
     *   contentHandler.startDocument();
     *   // set the XML elements and attributes into the result
     *   contentHandler.endDocument();
     * 
* * @param resultClass The class of the result, or null. * If resultClass is null, a vendor specific Result implementation will be returned. * The following classes are supported at a minimum: *
     *   javax.xml.transform.dom.DOMResult - returns a DOMResult
     *   javax.xml.transform.sax.SAXResult - returns a SAXResult
     *   javax.xml.transform.stax.StAXResult - returns a StAXResult
     *   javax.xml.transform.stream.StreamResult - returns a StreamResult
     * 
* @return Returns a Result for setting the XML value. * @throws SQLException if there is an error processing the XML value * or if this feature is not supported. * The getCause() method of the exception may provide a more detailed exception, for example, * if an XML parser exception occurs. * An exception is thrown if the state is not writable. * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since JDK 1.6 Build 79 */ public synchronized T setResult( Class resultClass) throws SQLException { checkClosed(); checkWritable(); final T result = createResult(resultClass); setReadable(true); setWritable(false); return result; } /** * @return that may be used to perform processing asynchronously. */ protected static ExecutorService getExecutorService() { if (JDBCSQLXML.executorService == null) { int corePoolSize = 1; int maximumPoolSize = 10; long keepAliveTime = 1; TimeUnit unit = TimeUnit.SECONDS; JDBCSQLXML.workQueue = new ArrayBlockingQueue(10); JDBCSQLXML.executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } return executorService; } /** * @return with which to obtain xml transformer instances. * @throws java.sql.SQLException when unable to obtain a factory instance. */ protected static TransformerFactory getTransformerFactory() throws SQLException { if (JDBCSQLXML.transformerFactory == null) { try { JDBCSQLXML.transformerFactory = TransformerFactory.newInstance(); } catch (TransformerFactoryConfigurationError ex) { throw Exceptions.transformFailed(ex); } } return JDBCSQLXML.transformerFactory; } /** * @return used to perform identity transforms * @throws java.sql.SQLException when unable to obtain the instance. */ protected static Transformer getIdentityTransformer() throws SQLException { if (JDBCSQLXML.identityTransformer == null) { try { JDBCSQLXML.identityTransformer = getTransformerFactory().newTransformer(); } catch (TransformerConfigurationException ex) { throw Exceptions.transformFailed(ex); } } return JDBCSQLXML.identityTransformer; } /** * @return with which to construct DOM implementation instances. * @throws java.sql.SQLException when unable to obtain a factory instance. */ protected static DOMImplementationRegistry getDOMImplementationRegistry() throws SQLException { if (domImplementationRegistry == null) { try { domImplementationRegistry = DOMImplementationRegistry.newInstance(); } catch (ClassCastException ex) { throw Exceptions.domInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.domInstantiation(ex); } catch (ClassNotFoundException ex) { throw Exceptions.domInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.domInstantiation(ex); } } return domImplementationRegistry; } /** * @return with which to create document instances. * @throws java.sql.SQLException when unable to obtain the DOM * implementation instance. */ protected static DOMImplementation getDOMImplementation() throws SQLException { if (domImplementation == null) { domImplementation = getDOMImplementationRegistry().getDOMImplementation( domFeatures); } if (domImplementation == null) { Exception ex = new RuntimeException("Not supported: " + domFeatures); throw Exceptions.domInstantiation(ex); } return domImplementation; } /** * @param namespaceURI of the document element to create or null. * @param qualifiedName of the document element to be created or null. * @param docType of document to be created or null. * When doctype is not null, its * Node.ownerDocument attribute is set to the document * being created. * @return with its document element. * If the NamespaceURI, qualifiedName, and * doctype are null, the returned * Document is empty with no document element. * @throws java.sql.SQLException wrapping any internal exception that occurs. * @see org.w3c.dom.DOMImplementation#createDocument(String,String,DocumentType) */ protected static Document createDocument(String namespaceURI, String qualifiedName, DocumentType docType) throws SQLException { try { return getDOMImplementation().createDocument(namespaceURI, qualifiedName, docType); } catch (DOMException ex) { throw Exceptions.domInstantiation(ex); } } /** * @return that is empty with no document element. * @throws java.sql.SQLException wrapping any internal exception that occurs. */ protected static Document createDocument() throws SQLException { return createDocument(null, null, null); } /** * Initializes this object's SQLXML value from the given Source * object.

* * @param source the Source representing the SQLXML value * @throws SQLException if the argument does not represent a * valid SQLXML value */ protected void init(Source source) throws SQLException { if (source == null) { throw JDBCUtil.nullArgument("source"); } Transformer transformer = JDBCSQLXML.getIdentityTransformer(); StreamResult result = new StreamResult(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gzos; try { gzos = new GZIPOutputStream(baos); } catch (IOException ex) { throw Exceptions.transformFailed(ex); } result.setOutputStream(gzos); try { transformer.transform(source, result); } catch (TransformerException ex) { throw Exceptions.transformFailed(ex); } try { gzos.close(); } catch (IOException ex) { throw Exceptions.transformFailed(ex); } byte[] data = baos.toByteArray(); setGZipData(data); setReadable(true); setWritable(false); } /** * Assigns this object's SQLXML value from the designated gzipped array * of bytes. * * @param data the SQLXML value * @throws java.sql.SQLException if the argument does not represent a * valid SQLXML value */ protected void setGZipData(byte[] data) throws SQLException { if (data == null) { throw JDBCUtil.nullArgument("data"); } this.gzdata = data; } /** * Directly retrieves this object's present SQLMXL value as a gzipped * array of bytes.

* * May be null, empty or invalid. * * @return this object's SQLMXL value as a gzipped byte array */ protected byte[] gZipData() { return this.gzdata; } /** * Retrieves this object's SQLXML value as a gzipped array of bytes, * possibly by terminating any in-progress write operations and converting * accumulated intermediate data. * * @throws java.sql.SQLException if an underlying I/O or transform * error occurs * @return this object's SQLXML value */ protected byte[] getGZipData() throws SQLException { byte[] bytes = gZipData(); if (bytes != null) { return bytes; } if (this.domResult != null) { DOMSource source = new DOMSource(domResult.getNode(), domResult.getSystemId()); OutputStream os = setBinaryStreamImpl(); StreamResult result = new StreamResult(os); try { JDBCSQLXML.identityTransformer.transform(source, result); } catch (TransformerException ex) { throw Exceptions.transformFailed(ex); } try { os.close(); } catch (IOException ex) { throw Exceptions.transformFailed(ex); } } if (this.outputStream == null) { throw Exceptions.notReadable("No Data."); } else if (!this.outputStream.isClosed()) { throw Exceptions.notReadable( "Stream used for writing must be closed but is still open."); } else if (this.outputStream.isFreed()) { throw Exceptions.notReadable( "Stream used for writing was freed and is no longer valid."); } try { setGZipData(this.outputStream.toByteArray()); return gZipData(); } catch (IOException ex) { throw Exceptions.notReadable(); } finally { this.freeOutputStream(); } } /** * closes this object and releases the resources that it holds. */ protected synchronized void close() { this.closed = true; setReadable(false); setWritable(false); freeOutputStream(); freeInputStream(); freeDomResult(); this.gzdata = null; } /** * Closes the input stream, if any, currently in use to read this object's * SQLXML value and nullifies the stream reference to make it eligible * for subsequent garbage collection. */ protected void freeInputStream() { if (this.inputStream != null) { try { this.inputStream.close(); } catch (IOException ex) { // ex.printStackTrace(); } finally { this.inputStream = null; } } } /** * Closes the output stream, if any, currently in use to write this object's * SQLXML value and nullifies the stream reference to make it eligible for * subsequent garbage collection. The stream's data buffer reference may * also be nullified, in order to make it eligible for garbage collection * immediately, just in case an external client still holds a reference to * the output stream. */ protected void freeOutputStream() { if (this.outputStream != null) { try { this.outputStream.free(); } catch (IOException ex) { // ex.printStackTrace(); } this.outputStream = null; } } /** * Checks whether this object is closed (has been freed). * * @throws java.sql.SQLException if this object is closed. */ protected synchronized void checkClosed() throws SQLException { if (this.closed) { throw Exceptions.inFreedState(); } } /** * Checks whether this object is readable. * * @throws java.sql.SQLException if this object is not readable. */ protected synchronized void checkReadable() throws SQLException { if (!this.isReadable()) { throw Exceptions.notReadable(); } } /** * Assigns this object's readability status. * * @param readable if true, then readable; else not readable */ protected synchronized void setReadable(boolean readable) { this.readable = readable; } /** * Checks whether this object is writable. * * @throws java.sql.SQLException if this object is not writable. */ protected synchronized void checkWritable() throws SQLException { if (!this.isWritable()) { throw Exceptions.notWritable(); } } /** * Assigns this object's writability status. * * @param writable if true, then writable; else not writable */ protected synchronized void setWritable(boolean writable) { this.writable = writable; } /** * Retrieves the object's readability status. * * @return if true, then readable; else not readable */ public synchronized boolean isReadable() { return this.readable; } /** * Retrieves the object's readability status. * * @return if true, then writable; else not writable */ public synchronized boolean isWritable() { return this.writable; } /** * Retrieves a stream representing the XML value designated by this * SQLXML instance.

* * @return a stream containing the XML data. * @throws SQLException if there is an error processing the XML value. */ protected InputStream getBinaryStreamImpl() throws SQLException { try { byte[] data = getGZipData(); ByteArrayInputStream bais = new ByteArrayInputStream(data); return new GZIPInputStream(bais); } catch (IOException ex) { throw Exceptions.transformFailed(ex); } } /** * Retrieves a reader representing the XML value designated by this * SQLXML instance.

* * @return a reader containing the XML data. * @throws SQLException if there is an error processing the XML value. */ protected Reader getCharacterStreamImpl() throws SQLException { return new InputStreamReader(getBinaryStreamImpl()); } /** * Retrieves a string representing the XML value designated by this * SQLXML instance.

* * @return a string containing the XML data. * @throws SQLException if there is an error processing the XML value. */ protected String getStringImpl() throws SQLException { try { return StringConverter.inputStreamToString(getBinaryStreamImpl(), "US-ASCII"); } catch (IOException ex) { throw Exceptions.transformFailed(ex); } } /** * Retrieves a stream to completely write the XML value this SQLXML * instance represents.

* * @return a stream to which the data can be written. * @throws SQLException if there is an error processing the XML value. */ protected OutputStream setBinaryStreamImpl() throws SQLException { this.outputStream = new ClosableByteArrayOutputStream(); try { return new GZIPOutputStream(this.outputStream); } catch (IOException ex) { this.outputStream = null; throw Exceptions.resultInstantiation(ex); } } /** * Retrieves a writer to completely write the XML value this SQLXML * instance represents.

* * @return a writer to which the data can be written. * @throws SQLException if there is an error processing the XML value. * The getCause() method of the exception may provide a more detailed exception, for example, * if the stream does not contain valid characters. * An exception is thrown if the state is not writable. * @since JDK 1.6 Build 79 */ protected Writer setCharacterStreamImpl() throws SQLException { return new OutputStreamWriter(setBinaryStreamImpl()); } /** * Sets the XML value designated by this SQLXML instance using the given * String representation.

* * @param value the XML value * @throws SQLException if there is an error processing the XML value. */ protected void setStringImpl(String value) throws SQLException { init(new StreamSource(new StringReader(value))); } /** * Returns a Source for reading the XML value designated by this SQLXML * instance.

* * @param sourceClass The class of the source, or null. If null, then a * DOMSource is returned. * @return a Source for reading the XML value. * @throws SQLException if there is an error processing the XML value * or if the given sourceClass is not supported. */ protected T getSourceImpl( Class sourceClass) throws SQLException { if (StreamSource.class.isAssignableFrom(sourceClass)) { return createStreamSource(sourceClass); } else if ((sourceClass == null) || DOMSource.class.isAssignableFrom(sourceClass)) { return createDOMSource(sourceClass); } else if (SAXSource.class.isAssignableFrom(sourceClass)) { return createSAXSource(sourceClass); } else if (StAXSource.class.isAssignableFrom(sourceClass)) { return createStAXSource(sourceClass); } throw JDBCUtil.invalidArgument("sourceClass: " + sourceClass); } /** * Retrieves a new StreamSource for reading the XML value designated by this * SQLXML instance.

* * @param sourceClass The class of the source * @throws java.sql.SQLException if there is an error processing the XML * value or if the given sourceClass is not supported. * @return a new StreamSource for reading the XML value designated by this * SQLXML instance */ @SuppressWarnings("unchecked") protected T createStreamSource( Class sourceClass) throws SQLException { StreamSource source; try { if (sourceClass == null) source = new StreamSource(); else { source = (StreamSource) sourceClass.getDeclaredConstructor().newInstance(); } } catch (SecurityException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.sourceInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.sourceInstantiation(ex); } catch (ClassCastException ex) { throw Exceptions.sourceInstantiation(ex); } catch (NoSuchMethodException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InvocationTargetException ex) { throw Exceptions.sourceInstantiation(ex); } Reader reader = getCharacterStreamImpl(); source.setReader(reader); return (T) source; } /** * Retrieves a new DOMSource for reading the XML value designated by this * SQLXML instance.

* * @param sourceClass The class of the source * @throws java.sql.SQLException if there is an error processing the XML * value or if the given sourceClass is not supported. * @return a new DOMSource for reading the XML value designated by this * SQLXML instance */ @SuppressWarnings("unchecked") protected T createDOMSource( Class sourceClass) throws SQLException { DOMSource source; try { if (sourceClass == null) source = new DOMSource(); else { source = (DOMSource) sourceClass.getDeclaredConstructor().newInstance(); } } catch (SecurityException ex) { throw Exceptions.sourceInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.sourceInstantiation(ex); } catch (ClassCastException ex) { throw Exceptions.sourceInstantiation(ex); } catch (NoSuchMethodException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InvocationTargetException ex) { throw Exceptions.sourceInstantiation(ex); } Transformer transformer = JDBCSQLXML.getIdentityTransformer(); InputStream stream = this.getBinaryStreamImpl(); StreamSource streamSource = new StreamSource(); DOMResult result = new DOMResult(); streamSource.setInputStream(stream); try { transformer.transform(streamSource, result); } catch (TransformerException ex) { throw Exceptions.transformFailed(ex); } source.setNode(result.getNode()); source.setSystemId(result.getSystemId()); return (T) source; } /** * Retrieves a new SAXSource for reading the XML value designated by this * SQLXML instance.

* * @param sourceClass The class of the source * @throws java.sql.SQLException if there is an error processing the XML * value or if the given sourceClass is not supported. * @return a new SAXSource for reading the XML value designated by this * SQLXML instance */ @SuppressWarnings("unchecked") protected T createSAXSource( Class sourceClass) throws SQLException { SAXSource source; try { if (sourceClass == null) source = new SAXSource(); else { source = (SAXSource) sourceClass.getDeclaredConstructor().newInstance(); } } catch (SecurityException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.sourceInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.sourceInstantiation(ex); } catch (ClassCastException ex) { throw Exceptions.sourceInstantiation(ex); } catch (NoSuchMethodException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InvocationTargetException ex) { throw Exceptions.sourceInstantiation(ex); } Reader reader = getCharacterStreamImpl(); InputSource inputSource = new InputSource(reader); source.setInputSource(inputSource); return (T) source; } /** * Retrieves a new StAXSource for reading the XML value designated by this * SQLXML instance.

* * @param sourceClass The class of the source * @throws java.sql.SQLException if there is an error processing the XML * value or if the given sourceClass is not supported. * @return a new StAXSource for reading the XML value designated by this * SQLXML instance */ @SuppressWarnings("unchecked") protected T createStAXSource( Class sourceClass) throws SQLException { StAXSource source = null; Constructor sourceCtor = null; Reader reader = null; XMLInputFactory factory = null; XMLEventReader eventReader = null; try { factory = XMLInputFactory.newInstance(); } catch (FactoryConfigurationError ex) { throw Exceptions.sourceInstantiation(ex); } try { sourceCtor = (sourceClass == null) ? StAXSource.class.getConstructor(XMLEventReader.class) : sourceClass.getConstructor(XMLEventReader.class); } catch (SecurityException ex) { throw Exceptions.sourceInstantiation(ex); } catch (NoSuchMethodException ex) { throw Exceptions.sourceInstantiation(ex); } reader = getCharacterStreamImpl(); try { eventReader = factory.createXMLEventReader(reader); } catch (XMLStreamException ex) { throw Exceptions.sourceInstantiation(ex); } try { source = (StAXSource) sourceCtor.newInstance(eventReader); } catch (SecurityException ex) { throw Exceptions.sourceInstantiation(ex); } catch (IllegalArgumentException ex) { throw Exceptions.sourceInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InvocationTargetException ex) { throw Exceptions.sourceInstantiation(ex.getTargetException()); } catch (ClassCastException ex) { throw Exceptions.sourceInstantiation(ex); } return (T) source; } /** * Retrieves a new Result for setting the XML value designated by this * SQLXML instance. * * @param resultClass The class of the result, or null. * @throws java.sql.SQLException if there is an error processing the XML * value or the state is not writable * @return for setting the XML value designated by this SQLXML instance. */ protected T createResult( Class resultClass) throws SQLException { checkWritable(); setWritable(false); setReadable(true); if ((resultClass == null) || StreamResult.class.isAssignableFrom(resultClass)) { return createStreamResult(resultClass); } else if (DOMResult.class.isAssignableFrom(resultClass)) { return createDOMResult(resultClass); } else if (SAXResult.class.isAssignableFrom(resultClass)) { return createSAXResult(resultClass); } else if (StAXResult.class.isAssignableFrom(resultClass)) { return createStAXResult(resultClass); } throw JDBCUtil.invalidArgument("resultClass: " + resultClass); } /** * Retrieves a new StreamResult for setting the XML value designated by this * SQLXML instance. * * @param resultClass The class of the result, or null. * @throws java.sql.SQLException if there is an error processing the XML * value * @return for setting the XML value designated by this SQLXML instance. */ // @SuppressWarnings("unchecked") protected T createStreamResult( Class resultClass) throws SQLException { StreamResult result; try { if (resultClass == null) result = new StreamResult(); else { result = (StreamResult) resultClass.getDeclaredConstructor().newInstance(); } } catch (SecurityException ex) { throw Exceptions.resultInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.resultInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.resultInstantiation(ex); } catch (ClassCastException ex) { throw Exceptions.resultInstantiation(ex); } catch (NoSuchMethodException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InvocationTargetException ex) { throw Exceptions.sourceInstantiation(ex); } OutputStream stream = setBinaryStreamImpl(); result.setOutputStream(stream); return (T) result; } /** * Retrieves a new DOMResult for setting the XML value designated by this * SQLXML instance. * * @param resultClass The class of the result, or null. * @throws java.sql.SQLException if there is an error processing the XML * value * @return for setting the XML value designated by this SQLXML instance. */ @SuppressWarnings("unchecked") protected T createDOMResult( Class resultClass) throws SQLException { try { T result; if (resultClass == null) result = (T) new DOMResult(); else { result = resultClass.getDeclaredConstructor().newInstance(); } this.domResult = (DOMResult) result; return result; } catch (SecurityException ex) { throw Exceptions.resultInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.resultInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.resultInstantiation(ex); } catch (ClassCastException ex) { throw Exceptions.resultInstantiation(ex); } catch (NoSuchMethodException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InvocationTargetException ex) { throw Exceptions.sourceInstantiation(ex); } } /** * Retrieves a new SAXResult for setting the XML value designated by this * SQLXML instance. * * @param resultClass The class of the result, or null. * @throws java.sql.SQLException if there is an error processing the XML * value * @return for setting the XML value designated by this SQLXML instance. */ @SuppressWarnings("unchecked") protected T createSAXResult( Class resultClass) throws SQLException { SAXResult result = null; try { if (resultClass == null) result = new SAXResult(); else { result = (SAXResult) resultClass.getDeclaredConstructor().newInstance(); } } catch (SecurityException ex) { throw Exceptions.resultInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.resultInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.resultInstantiation(ex); } catch (ClassCastException ex) { throw Exceptions.resultInstantiation(ex); } catch (NoSuchMethodException ex) { throw Exceptions.sourceInstantiation(ex); } catch (InvocationTargetException ex) { throw Exceptions.sourceInstantiation(ex); } SAX2DOMBuilder handler = null; try { handler = new SAX2DOMBuilder(); } catch (ParserConfigurationException ex) { throw Exceptions.resultInstantiation(ex); } this.domResult = new DOMResult(); result.setHandler(handler); this.domResult.setNode(handler.getDocument()); return (T) result; } /** * Retrieves a new DOMResult for setting the XML value designated by this * SQLXML instance. * * @param resultClass The class of the result, or null. * @throws java.sql.SQLException if there is an error processing the XML * value * @return for setting the XML value designated by this SQLXML instance. */ @SuppressWarnings("unchecked") protected T createStAXResult( Class resultClass) throws SQLException { StAXResult result = null; try { this.domResult = new DOMResult((new SAX2DOMBuilder()).getDocument()); XMLOutputFactory factory = XMLOutputFactory.newInstance(); XMLStreamWriter xmlStreamWriter = factory.createXMLStreamWriter(this.domResult); if (resultClass == null || resultClass == StAXResult.class) { result = new StAXResult(xmlStreamWriter); } else { Constructor ctor = resultClass.getConstructor(XMLStreamWriter.class); result = (StAXResult) ctor.newInstance(xmlStreamWriter); } } catch (ParserConfigurationException ex) { throw Exceptions.resultInstantiation(ex); } catch (SecurityException ex) { throw Exceptions.resultInstantiation(ex); } catch (IllegalArgumentException ex) { throw Exceptions.resultInstantiation(ex); } catch (IllegalAccessException ex) { throw Exceptions.resultInstantiation(ex); } catch (InvocationTargetException ex) { throw Exceptions.resultInstantiation(ex.getTargetException()); } catch (FactoryConfigurationError ex) { throw Exceptions.resultInstantiation(ex); } catch (InstantiationException ex) { throw Exceptions.resultInstantiation(ex); } catch (NoSuchMethodException ex) { throw Exceptions.resultInstantiation(ex); } catch (XMLStreamException ex) { throw Exceptions.resultInstantiation(ex); } return (T) result; } protected void freeDomResult() { this.domResult = null; } /** * Basically just a namespace to isolate SQLXML exception generation */ protected static class Exceptions { /** * Construction Disabled. */ private Exceptions() { } /** * Retrieves a new SQLXML DOM instantiation exception. * * @param cause of the exception */ static SQLException domInstantiation(Throwable cause) { Exception ex = (cause instanceof Exception) ? (Exception) cause : new Exception(cause); return JDBCUtil.sqlException(ErrorCode.GENERAL_ERROR, "SQLXML DOM instantiation failed: " + cause, ex); } /** * Retrieves a new SQLXML source instantiation exception. * * @param cause of the exception. * @return a new SQLXML source instantiation exception */ static SQLException sourceInstantiation(Throwable cause) { Exception ex = (cause instanceof Exception) ? (Exception) cause : new Exception(cause); return JDBCUtil.sqlException(ErrorCode.GENERAL_ERROR, "SQLXML Source instantiation failed: " + cause, ex); } /** * Retrieves a new SQLXML result instantiation exception. * * @param cause of the exception. * @return a new SQLXML result instantiation exception */ static SQLException resultInstantiation(Throwable cause) { Exception ex = (cause instanceof Exception) ? (Exception) cause : new Exception(cause); return JDBCUtil.sqlException(ErrorCode.GENERAL_ERROR, "SQLXML Result instantiation failed: " + cause, ex); } /** * Retrieves a new SQLXML parse failed exception. * * @param cause of the exception. * @return a new SQLXML parse failed exception */ static SQLException parseFailed(Throwable cause) { Exception ex = (cause instanceof Exception) ? (Exception) cause : new Exception(cause); return JDBCUtil.sqlException(ErrorCode.GENERAL_ERROR, "parse failed: " + cause, ex); } /** * Retrieves a new SQLXML transform failed exception. * * @param cause of the exception. * @return a new SQLXML parse failed exception */ static SQLException transformFailed(Throwable cause) { Exception ex = (cause instanceof Exception) ? (Exception) cause : new Exception(cause); return JDBCUtil.sqlException(ErrorCode.GENERAL_ERROR, "transform failed: " + cause, ex); } /** * Retrieves a new SQLXML not readable exception. * * @return a new SQLXML not readable exception */ static SQLException notReadable() { return JDBCUtil.sqlException(ErrorCode.GENERAL_IO_ERROR, "SQLXML in not readable state"); } /** * Retrieves a new SQLXML not readable exception. * * @return a new SQLXML not readable exception */ static SQLException notReadable(String reason) { return JDBCUtil.sqlException(ErrorCode.GENERAL_IO_ERROR, "SQLXML in not readable state: " + reason); } /** * Retrieves a new SQLXML not writable exception. * * @return a new SQLXML not writable exception */ static SQLException notWritable() { return JDBCUtil.sqlException(ErrorCode.GENERAL_IO_ERROR, "SQLXML in not writable state"); } /** * Currently unused. * * @return never */ static SQLException directUpdateByLocatorNotSupported() { return JDBCUtil.sqlException(ErrorCode.X_0A000, "SQLXML direct update by locator"); } /** * Retrieves a new SQLXML in freed state exception. * * @return a new SQLXML in freed state exception */ static SQLException inFreedState() { return JDBCUtil.sqlException(ErrorCode.GENERAL_ERROR, "SQLXML in freed state"); } } // ------------------------------------------------------------------------- /** * Builds a DOM from SAX events. */ protected static class SAX2DOMBuilder implements ContentHandler, Closeable { /** * */ private boolean closed; /** * */ private Element currentElement; // --------------------- internal implementation ----------------------- /** * */ private Node currentNode; /** * */ private Document document; /** * */ private Locator locator; /** *

Creates a new instance of SAX2DOMBuilder, which creates * a new document. The document is available via * {@link #getDocument()}.

* @throws javax.xml.parsers.ParserConfigurationException */ public SAX2DOMBuilder() throws ParserConfigurationException { DocumentBuilderFactory documentBuilderFactory; DocumentBuilder documentBuilder; documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setValidating(false); documentBuilderFactory.setNamespaceAware(true); documentBuilder = documentBuilderFactory.newDocumentBuilder(); this.document = documentBuilder.newDocument(); this.currentNode = this.document; } /** * Receive an object for locating the origin of SAX document events. * *

SAX parsers are strongly encouraged (though not absolutely * required) to supply a locator: if it does so, it must supply * the locator to the application by invoking this method before * invoking any of the other methods in the ContentHandler * interface.

* *

The locator allows the application to determine the end * position of any document-related event, even if the parser is * not reporting an error. Typically, the application will * use this information for reporting its own errors (such as * character content that does not match an application's * business rules). The information returned by the locator * is probably not sufficient for use with a search engine.

* *

Note that the locator will return correct information only * during the invocation SAX event callbacks after * {@link #startDocument startDocument} returns and before * {@link #endDocument endDocument} is called. The * application should not attempt to use it at any other time.

* * @param locator an object that can return the location of * any SAX document event * @see org.xml.sax.Locator */ public void setDocumentLocator(Locator locator) { this.locator = locator; } /** * Retrieves the Locator.

* @return the Locator */ public Locator getDocumentLocator() { return this.locator; } /** * Receive notification of the beginning of a document. * *

The SAX parser will invoke this method only once, before any * other event callbacks (except for {@link #setDocumentLocator * setDocumentLocator}).

* * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #endDocument */ public void startDocument() throws SAXException { checkClosed(); } /** * Receive notification of the end of a document. * *

There is an apparent contradiction between the * documentation for this method and the documentation for {@link * org.xml.sax.ErrorHandler#fatalError}. Until this ambiguity is * resolved in a future major release, clients should make no * assumptions about whether endDocument() will or will not be * invoked when the parser has reported a fatalError() or thrown * an exception.

* *

The SAX parser will invoke this method only once, and it will * be the last method invoked during the parse. The parser shall * not invoke this method until it has either abandoned parsing * (because of an unrecoverable error) or reached the end of * input.

* * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #startDocument */ public void endDocument() throws SAXException { checkClosed(); close(); } /** * Begin the scope of a prefix-URI Namespace mapping. * *

The information from this event is not necessary for * normal Namespace processing: the SAX XML reader will * automatically replace prefixes for element and attribute * names when the http://xml.org/sax/features/namespaces * feature is true (the default).

* *

There are cases, however, when applications need to * use prefixes in character data or in attribute values, * where they cannot safely be expanded automatically; the * start/endPrefixMapping event supplies the information * to the application to expand prefixes in those contexts * itself, if necessary.

* *

Note that start/endPrefixMapping events are not * guaranteed to be properly nested relative to each other: * all startPrefixMapping events will occur immediately before the * corresponding {@link #startElement startElement} event, * and all {@link #endPrefixMapping endPrefixMapping} * events will occur immediately after the corresponding * {@link #endElement endElement} event, * but their order is not otherwise * guaranteed.

* *

There should never be start/endPrefixMapping events for the * "xml" prefix, since it is predeclared and immutable.

* * @param prefix the Namespace prefix being declared. * An empty string is used for the default element namespace, * which has no prefix. * @param uri the Namespace URI the prefix is mapped to * @throws org.xml.sax.SAXException the client may throw * an exception during processing * @see #endPrefixMapping * @see #startElement */ public void startPrefixMapping(String prefix, String uri) throws SAXException { checkClosed(); } /** * End the scope of a prefix-URI mapping. * *

See {@link #startPrefixMapping startPrefixMapping} for * details. These events will always occur immediately after the * corresponding {@link #endElement endElement} event, but the order of * {@link #endPrefixMapping endPrefixMapping} events is not otherwise * guaranteed.

* * @param prefix the prefix that was being mapped. * This is the empty string when a default mapping scope ends. * @throws org.xml.sax.SAXException the client may throw * an exception during processing * @see #startPrefixMapping * @see #endElement */ public void endPrefixMapping(String prefix) throws SAXException { checkClosed(); } /** * Receive notification of the beginning of an element. * *

The Parser will invoke this method at the beginning of every * element in the XML document; there will be a corresponding * {@link #endElement endElement} event for every startElement event * (even when the element is empty). All of the element's content will be * reported, in order, before the corresponding endElement * event.

* *

This event allows up to three name components for each * element:

* *
    *
  1. the Namespace URI;
  2. *
  3. the local name; and
  4. *
  5. the qualified (prefixed) name.
  6. *
* *

Any or all of these may be provided, depending on the * values of the http://xml.org/sax/features/namespaces * and the http://xml.org/sax/features/namespace-prefixes * properties:

* *
    *
  • the Namespace URI and local name are required when * the namespaces property is true (the default), and are * optional when the namespaces property is false (if one is * specified, both must be);
  • *
  • the qualified name is required when the namespace-prefixes property * is true, and is optional when the namespace-prefixes property * is false (the default).
  • *
* *

Note that the attribute list provided will contain only * attributes with explicit values (specified or defaulted): * #IMPLIED attributes will be omitted. The attribute list * will contain attributes used for Namespace declarations * (xmlns* attributes) only if the * http://xml.org/sax/features/namespace-prefixes * property is true (it is false by default, and support for a * true value is optional).

* *

Like {@link #characters characters()}, attribute values may have * characters that need more than one char value.

* * @param uri the Namespace URI, or the empty string if the * element has no Namespace URI or if Namespace * processing is not being performed * @param localName the local name (without prefix), or the * empty string if Namespace processing is not being * performed * @param qName the qualified name (with prefix), or the * empty string if qualified names are not available * @param atts the attributes attached to the element. If * there are no attributes, it shall be an empty * Attributes object. The value of this object after * startElement returns is undefined * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #endElement * @see org.xml.sax.Attributes * @see org.xml.sax.helpers.AttributesImpl */ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { checkClosed(); Element element; if ((uri == null) || (uri.length() == 0)) { element = getDocument().createElement(qName); } else { element = getDocument().createElementNS(uri, qName); } if (atts != null) { for (int i = 0; i < atts.getLength(); i++) { String attrURI = atts.getURI(i); String attrQName = atts.getQName(i); String attrValue = atts.getValue(i); if ((attrURI == null) || (attrURI.length() == 0)) { element.setAttribute(attrQName, attrValue); } else { element.setAttributeNS(attrURI, attrQName, attrValue); } } } getCurrentNode().appendChild(element); setCurrentNode(element); if (getCurrentElement() == null) { setCurrentElement(element); } } /** * Receive notification of the end of an element. * *

The SAX parser will invoke this method at the end of every * element in the XML document; there will be a corresponding * {@link #startElement startElement} event for every endElement * event (even when the element is empty).

* *

For information on the names, see startElement.

* * @param uri the Namespace URI, or the empty string if the * element has no Namespace URI or if Namespace * processing is not being performed * @param localName the local name (without prefix), or the * empty string if Namespace processing is not being * performed * @param qName the qualified XML name (with prefix), or the * empty string if qualified names are not available * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception */ public void endElement(String uri, String localName, String qName) throws SAXException { checkClosed(); setCurrentNode(getCurrentNode().getParentNode()); } /** * Receive notification of character data. * *

The Parser will call this method to report each chunk of * character data. SAX parsers may return all contiguous character * data in a single chunk, or they may split it into several * chunks; however, all of the characters in any single event * must come from the same external entity so that the Locator * provides useful information.

* *

The application must not attempt to read from the array * outside of the specified range.

* *

Individual characters may consist of more than one Java * char value. There are two important cases where this * happens, because characters can't be represented in just sixteen bits. * In one case, characters are represented in a Surrogate Pair, * using two special Unicode values. Such characters are in the so-called * "Astral Planes", with a code point above U+FFFF. A second case involves * composite characters, such as a base character combining with one or * more accent characters.

* *

Your code should not assume that algorithms using * char-at-a-time idioms will be working in character * units; in some cases they will split characters. This is relevant * wherever XML permits arbitrary characters, such as attribute values, * processing instruction data, and comments as well as in data reported * from this method. It's also generally relevant whenever Java code * manipulates internationalized text; the issue isn't unique to XML.

* *

Note that some parsers will report whitespace in element * content using the {@link #ignorableWhitespace ignorableWhitespace} * method rather than this one (validating parsers must * do so).

* * @param ch the characters from the XML document * @param start the start position in the array * @param length the number of characters to read from the array * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #ignorableWhitespace * @see org.xml.sax.Locator */ public void characters(char[] ch, int start, int length) throws SAXException { checkClosed(); Node node = getCurrentNode().getLastChild(); String s = new String(ch, start, length); if ((node != null) && (node.getNodeType() == Node.TEXT_NODE)) { ((Text) node).appendData(s); } else { Text text = getDocument().createTextNode(s); getCurrentNode().appendChild(text); } } /** * Receive notification of ignorable whitespace in element content. * *

Validating Parsers must use this method to report each chunk * of whitespace in element content (see the W3C XML 1.0 * recommendation, section 2.10): non-validating parsers may also * use this method if they are capable of parsing and using * content models.

* *

SAX parsers may return all contiguous whitespace in a single * chunk, or they may split it into several chunks; however, all of * the characters in any single event must come from the same * external entity, so that the Locator provides useful * information.

* *

The application must not attempt to read from the array * outside of the specified range.

* * @param ch the characters from the XML document * @param start the start position in the array * @param length the number of characters to read from the array * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #characters */ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { characters(ch, start, length); } /** * Receive notification of a processing instruction. * *

The Parser will invoke this method once for each processing * instruction found: note that processing instructions may occur * before or after the main document element.

* *

A SAX parser must never report an XML declaration (XML 1.0, * section 2.8) or a text declaration (XML 1.0, section 4.3.1) * using this method.

* *

Like {@link #characters characters()}, processing instruction * data may have characters that need more than one char * value.

* * @param target the processing instruction target * @param data the processing instruction data, or null if * none was supplied. The data does not include any * whitespace separating it from the target * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception */ public void processingInstruction(String target, String data) throws SAXException { checkClosed(); ProcessingInstruction processingInstruction; processingInstruction = getDocument().createProcessingInstruction(target, data); getCurrentNode().appendChild(processingInstruction); } /** * Receive notification of a skipped entity. * This is not called for entity references within markup constructs * such as element start tags or markup declarations. (The XML * recommendation requires reporting skipped external entities. * SAX also reports internal entity expansion/non-expansion, except * within markup constructs.) * *

The Parser will invoke this method each time the entity is * skipped. Non-validating processors may skip entities if they * have not seen the declarations (because, for example, the * entity was declared in an external DTD subset). All processors * may skip external entities, depending on the values of the * http://xml.org/sax/features/external-general-entities * and the * http://xml.org/sax/features/external-parameter-entities * properties.

* * @param name the name of the skipped entity. If it is a * parameter entity, the name will begin with '%', and if * it is the external DTD subset, it will be the string * "[dtd]" * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception */ public void skippedEntity(String name) throws SAXException { checkClosed(); EntityReference entityReference = getDocument().createEntityReference(name); getCurrentNode().appendChild(entityReference); } /** * Closes this DOMBuilder. */ public void close() { this.closed = true; } /** * Frees the DOMBuilder. */ public void free() { close(); this.document = null; this.currentElement = null; this.currentNode = null; this.locator = null; } /** * Retrieves whether this DOMBuilder is closed. * * @return boolean */ public boolean isClosed() { return this.closed; } /** * Checks whether this DOMBuilder is closed. * * @throws SAXException if this DOMBuilder is closed. */ protected void checkClosed() throws SAXException { if (isClosed()) { throw new SAXException("content handler is closed."); // NOI18N } } /** * Retrieves the document. * * @return Document */ public Document getDocument() { return this.document; } /** * Retrieves the current element.

*/ protected Element getCurrentElement() { return this.currentElement; } /** * Assigns the current element. * @param element */ protected void setCurrentElement(Element element) { this.currentElement = element; } /** * Retrieves the current node.

*/ protected Node getCurrentNode() { return this.currentNode; } /** * Assigns the current node.

* @param node */ protected void setCurrentNode(Node node) { this.currentNode = node; } } /** * Writes to a {@link javax.xml.stream.XMLStreamWriter XMLStreamWriter} * from SAX events. */ public static class SAX2XMLStreamWriter implements ContentHandler, Closeable { /** * Namespace declarations for an upcoming element. */ private List namespaces = new ArrayList(); /** * Whether this object is closed. */ private boolean closed; /** * This object's SAX locator. */ private Locator locator; /** * XML stream writer where events are pushed. */ private XMLStreamWriter writer; /** * Constructs a new SAX2XMLStreamWriter that writes SAX events to the * designated XMLStreamWriter. * * @param writer the writer to which to write SAX events */ public SAX2XMLStreamWriter(XMLStreamWriter writer) { if (writer == null) { throw new NullPointerException("writer"); } this.writer = writer; } /** * Receive notification of the beginning of a document. * *

The SAX parser will invoke this method only once, before any * other event callbacks (except for {@link #setDocumentLocator * setDocumentLocator}).

* * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #endDocument */ public void startDocument() throws SAXException { checkClosed(); try { this.writer.writeStartDocument(); } catch (XMLStreamException e) { throw new SAXException(e); } } /** * Receive notification of the end of a document. * *

There is an apparent contradiction between the * documentation for this method and the documentation for {@link * org.xml.sax.ErrorHandler#fatalError}. Until this ambiguity is * resolved in a future major release, clients should make no * assumptions about whether endDocument() will or will not be * invoked when the parser has reported a fatalError() or thrown * an exception.

* *

The SAX parser will invoke this method only once, and it will * be the last method invoked during the parse. The parser shall * not invoke this method until it has either abandoned parsing * (because of an unrecoverable error) or reached the end of * input.

* * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #startDocument */ public void endDocument() throws SAXException { checkClosed(); try { this.writer.writeEndDocument(); this.writer.flush(); } catch (XMLStreamException e) { throw new SAXException(e); } } /** * Receive notification of character data. * *

The Parser will call this method to report each chunk of * character data. SAX parsers may return all contiguous character * data in a single chunk, or they may split it into several * chunks; however, all of the characters in any single event * must come from the same external entity so that the Locator * provides useful information.

* *

The application must not attempt to read from the array * outside of the specified range.

* *

Individual characters may consist of more than one Java * char value. There are two important cases where this * happens, because characters can't be represented in just sixteen bits. * In one case, characters are represented in a Surrogate Pair, * using two special Unicode values. Such characters are in the so-called * "Astral Planes", with a code point above U+FFFF. A second case involves * composite characters, such as a base character combining with one or * more accent characters.

* *

Your code should not assume that algorithms using * char-at-a-time idioms will be working in character * units; in some cases they will split characters. This is relevant * wherever XML permits arbitrary characters, such as attribute values, * processing instruction data, and comments as well as in data reported * from this method. It's also generally relevant whenever Java code * manipulates internationalized text; the issue isn't unique to XML.

* *

Note that some parsers will report whitespace in element * content using the {@link #ignorableWhitespace ignorableWhitespace} * method rather than this one (validating parsers must * do so).

* * @param ch the characters from the XML document * @param start the start position in the array * @param length the number of characters to read from the array * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #ignorableWhitespace * @see org.xml.sax.Locator */ public void characters(char[] ch, int start, int length) throws SAXException { checkClosed(); try { this.writer.writeCharacters(ch, start, length); } catch (XMLStreamException e) { throw new SAXException(e); } } /** * Receive notification of the beginning of an element. * *

The Parser will invoke this method at the beginning of every * element in the XML document; there will be a corresponding * {@link #endElement endElement} event for every startElement event * (even when the element is empty). All of the element's content will be * reported, in order, before the corresponding endElement * event.

* *

This event allows up to three name components for each * element:

* *
    *
  1. the Namespace URI;
  2. *
  3. the local name; and
  4. *
  5. the qualified (prefixed) name.
  6. *
* *

Any or all of these may be provided, depending on the * values of the http://xml.org/sax/features/namespaces * and the http://xml.org/sax/features/namespace-prefixes * properties:

* *
    *
  • the Namespace URI and local name are required when * the namespaces property is true (the default), and are * optional when the namespaces property is false (if one is * specified, both must be);
  • *
  • the qualified name is required when the namespace-prefixes property * is true, and is optional when the namespace-prefixes property * is false (the default).
  • *
* *

Note that the attribute list provided will contain only * attributes with explicit values (specified or defaulted): * #IMPLIED attributes will be omitted. The attribute list * will contain attributes used for Namespace declarations * (xmlns* attributes) only if the * http://xml.org/sax/features/namespace-prefixes * property is true (it is false by default, and support for a * true value is optional).

* *

Like {@link #characters characters()}, attribute values may have * characters that need more than one char value.

* * @param namespaceURI the Namespace URI, or the empty string if the * element has no Namespace URI or if Namespace * processing is not being performed * @param localName the local name (without prefix), or the * empty string if Namespace processing is not being * performed * @param qName the qualified name (with prefix), or the * empty string if qualified names are not available * @param atts the attributes attached to the element. If * there are no attributes, it shall be an empty * Attributes object. The value of this object after * startElement returns is undefined * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #endElement * @see org.xml.sax.Attributes * @see org.xml.sax.helpers.AttributesImpl */ public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { checkClosed(); try { int qi = qName.indexOf(':'); String prefix = (qi > 0) ? qName.substring(0, qi) : ""; this.writer.writeStartElement(prefix, localName, namespaceURI); int length = namespaces.size(); for (int i = 0; i < length; i++) { QualifiedName ns = namespaces.get(i); this.writer.writeNamespace(ns.prefix, ns.namespaceName); } namespaces.clear(); length = atts.getLength(); for (int i = 0; i < length; i++) { this.writer.writeAttribute(atts.getURI(i), atts.getLocalName(i), atts.getValue(i)); } } catch (XMLStreamException e) { throw new SAXException(e); } } /** * Receive notification of the end of an element. * *

The SAX parser will invoke this method at the end of every * element in the XML document; there will be a corresponding * {@link #startElement startElement} event for every endElement * event (even when the element is empty).

* *

For information on the names, see startElement.

* * @param namespaceURI the Namespace URI, or the empty string if the * element has no Namespace URI or if Namespace * processing is not being performed * @param localName the local name (without prefix), or the * empty string if Namespace processing is not being * performed * @param qName the qualified XML name (with prefix), or the * empty string if qualified names are not available * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception */ public void endElement(String namespaceURI, String localName, String qName) throws SAXException { checkClosed(); try { this.writer.writeEndElement(); } catch (XMLStreamException e) { throw new SAXException(e); } } /** * Begin the scope of a prefix-URI Namespace mapping. * *

The information from this event is not necessary for * normal Namespace processing: the SAX XML reader will * automatically replace prefixes for element and attribute * names when the http://xml.org/sax/features/namespaces * feature is true (the default).

* *

There are cases, however, when applications need to * use prefixes in character data or in attribute values, * where they cannot safely be expanded automatically; the * start/endPrefixMapping event supplies the information * to the application to expand prefixes in those contexts * itself, if necessary.

* *

Note that start/endPrefixMapping events are not * guaranteed to be properly nested relative to each other: * all startPrefixMapping events will occur immediately before the * corresponding {@link #startElement startElement} event, * and all {@link #endPrefixMapping endPrefixMapping} * events will occur immediately after the corresponding * {@link #endElement endElement} event, * but their order is not otherwise * guaranteed.

* *

There should never be start/endPrefixMapping events for the * "xml" prefix, since it is predeclared and immutable.

* * @param prefix the Namespace prefix being declared. * An empty string is used for the default element namespace, * which has no prefix. * @param uri the Namespace URI the prefix is mapped to * @throws org.xml.sax.SAXException the client may throw * an exception during processing * @see #endPrefixMapping * @see #startElement */ public void startPrefixMapping(String prefix, String uri) throws SAXException { checkClosed(); try { this.writer.setPrefix(prefix, uri); namespaces.add(new QualifiedName(prefix, uri)); } catch (XMLStreamException e) { throw new SAXException(e); } } /** * End the scope of a prefix-URI mapping. * *

See {@link #startPrefixMapping startPrefixMapping} for * details. These events will always occur immediately after the * corresponding {@link #endElement endElement} event, but the order of * {@link #endPrefixMapping endPrefixMapping} events is not otherwise * guaranteed.

* * @param prefix the prefix that was being mapped. * This is the empty string when a default mapping scope ends. * @throws org.xml.sax.SAXException the client may throw * an exception during processing * @see #startPrefixMapping * @see #endElement */ public void endPrefixMapping(String prefix) throws SAXException { checkClosed(); // } /** * Receive notification of ignorable whitespace in element content. * *

Validating Parsers must use this method to report each chunk * of whitespace in element content (see the W3C XML 1.0 * recommendation, section 2.10): non-validating parsers may also * use this method if they are capable of parsing and using * content models.

* *

SAX parsers may return all contiguous whitespace in a single * chunk, or they may split it into several chunks; however, all of * the characters in any single event must come from the same * external entity, so that the Locator provides useful * information.

* *

The application must not attempt to read from the array * outside of the specified range.

* * @param ch the characters from the XML document * @param start the start position in the array * @param length the number of characters to read from the array * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception * @see #characters */ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { characters(ch, start, length); } /** * Receive notification of a processing instruction. * *

The Parser will invoke this method once for each processing * instruction found: note that processing instructions may occur * before or after the main document element.

* *

A SAX parser must never report an XML declaration (XML 1.0, * section 2.8) or a text declaration (XML 1.0, section 4.3.1) * using this method.

* *

Like {@link #characters characters()}, processing instruction * data may have characters that need more than one char * value.

* * @param target the processing instruction target * @param data the processing instruction data, or null if * none was supplied. The data does not include any * whitespace separating it from the target * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception */ public void processingInstruction(String target, String data) throws SAXException { checkClosed(); try { this.writer.writeProcessingInstruction(target, data); } catch (XMLStreamException e) { throw new SAXException(e); } } /** * Receive an object for locating the origin of SAX document events. * *

SAX parsers are strongly encouraged (though not absolutely * required) to supply a locator: if it does so, it must supply * the locator to the application by invoking this method before * invoking any of the other methods in the ContentHandler * interface.

* *

The locator allows the application to determine the end * position of any document-related event, even if the parser is * not reporting an error. Typically, the application will * use this information for reporting its own errors (such as * character content that does not match an application's * business rules). The information returned by the locator * is probably not sufficient for use with a search engine.

* *

Note that the locator will return correct information only * during the invocation SAX event callbacks after * {@link #startDocument startDocument} returns and before * {@link #endDocument endDocument} is called. The * application should not attempt to use it at any other time.

* * @param locator an object that can return the location of * any SAX document event * @see org.xml.sax.Locator */ public void setDocumentLocator(Locator locator) { this.locator = locator; } /** * Retrieves the Locator.

* @return the Locator */ public Locator getDocumentLocator() { return this.locator; } /** * Receive notification of a skipped entity. * This is not called for entity references within markup constructs * such as element start tags or markup declarations. (The XML * recommendation requires reporting skipped external entities. * SAX also reports internal entity expansion/non-expansion, except * within markup constructs.) * *

The Parser will invoke this method each time the entity is * skipped. Non-validating processors may skip entities if they * have not seen the declarations (because, for example, the * entity was declared in an external DTD subset). All processors * may skip external entities, depending on the values of the * http://xml.org/sax/features/external-general-entities * and the * http://xml.org/sax/features/external-parameter-entities * properties.

* * @param name the name of the skipped entity. If it is a * parameter entity, the name will begin with '%', and if * it is the external DTD subset, it will be the string * "[dtd]" * @throws org.xml.sax.SAXException any SAX exception, possibly * wrapping another exception */ public void skippedEntity(String name) throws SAXException { checkClosed(); // } public void comment(char[] ch, int start, int length) throws SAXException { checkClosed(); try { this.writer.writeComment(new String(ch, start, length)); } catch (XMLStreamException e) { throw new SAXException(e); } } public XMLStreamWriter getWriter() { return this.writer; } protected List getNamespaces() { return this.namespaces; } /** * Closes this object. */ public void close() throws IOException { if (!this.closed) { this.closed = true; try { this.writer.close(); } catch (XMLStreamException e) { throw new IOException(e); } finally { this.writer = null; this.locator = null; this.namespaces = null; } } } /** * Retrieves whether this object is closed. * * @return boolean */ public boolean isClosed() { return this.closed; } /** * Checks whether this object is closed. * * @throws SAXException if this DOMBuilder is closed. */ protected void checkClosed() throws SAXException { if (isClosed()) { throw new SAXException("content handler is closed."); // NOI18N } } // --------------------- internal implementation ----------------------- protected static class QualifiedName { public final String namespaceName; public final String prefix; public QualifiedName(final String prefix, final String namespaceName) { this.prefix = prefix; this.namespaceName = namespaceName; } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy