1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
|
package org.postgresql.jdbc4;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLState;
import org.postgresql.util.PSQLException;
import org.postgresql.core.BaseConnection;
import java.io.*;
import java.sql.SQLXML;
import java.sql.SQLException;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.dom.DOMResult;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXResult;
import org.xml.sax.InputSource;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stax.StAXResult;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.XMLStreamException;
public class Jdbc4SQLXML implements SQLXML {
private final BaseConnection _conn;
private String _data; // The actual data contained.
private boolean _initialized; // Has someone assigned the data for this object?
private boolean _active; // Is anyone in the process of loading data into us?
private boolean _freed;
private ByteArrayOutputStream _byteArrayOutputStream;
private StringWriter _stringWriter;
private DOMResult _domResult;
public Jdbc4SQLXML(BaseConnection conn)
{
this(conn, null, false);
}
public Jdbc4SQLXML(BaseConnection conn, String data)
{
this(conn, data, true);
}
private Jdbc4SQLXML(BaseConnection conn, String data, boolean initialized)
{
_conn = conn;
_data = data;
_initialized = initialized;
_active = false;
_freed = false;
}
public synchronized void free()
{
_freed = true;
_data = null;
}
public synchronized InputStream getBinaryStream() throws SQLException
{
checkFreed();
ensureInitialized();
if (_data == null)
return null;
try {
return new ByteArrayInputStream(_conn.getEncoding().encode(_data));
} catch (IOException ioe) {
// This should be a can't happen exception. We just
// decoded this data, so it would be surprising that
// we couldn't encode it.
// For this reason don't make it translatable.
throw new PSQLException("Failed to re-encode xml data.", PSQLState.DATA_ERROR, ioe);
}
}
public synchronized Reader getCharacterStream() throws SQLException
{
checkFreed();
ensureInitialized();
if (_data == null)
return null;
return new StringReader(_data);
}
// We must implement this unsafely because that's what the
// interface requires. Because it says we're returning T
// which is unknown, none of the return values can satisfy it
// as Java isn't going to understand the if statements that
// ensure they are the same.
//
public synchronized Source getSource(Class sourceClass) throws SQLException
{
checkFreed();
ensureInitialized();
if (_data == null)
return null;
try {
if (sourceClass == null || DOMSource.class.equals(sourceClass))
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new NonPrintingErrorHandler());
InputSource input = new InputSource(new StringReader(_data));
return new DOMSource(builder.parse(input));
}
else if (SAXSource.class.equals(sourceClass))
{
InputSource is = new InputSource(new StringReader(_data));
return new SAXSource(is);
}
else if (StreamSource.class.equals(sourceClass))
{
return new StreamSource(new StringReader(_data));
}
else if (StAXSource.class.equals(sourceClass))
{
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(_data));
return new StAXSource(xsr);
}
} catch (Exception e) {
throw new PSQLException(GT.tr("Unable to decode xml data."), PSQLState.DATA_ERROR, e);
}
throw new PSQLException(GT.tr("Unknown XML Source class: {0}", sourceClass), PSQLState.INVALID_PARAMETER_TYPE);
}
public synchronized String getString() throws SQLException
{
checkFreed();
ensureInitialized();
return _data;
}
public synchronized OutputStream setBinaryStream() throws SQLException
{
checkFreed();
initialize();
_active = true;
_byteArrayOutputStream = new ByteArrayOutputStream();
return _byteArrayOutputStream;
}
public synchronized Writer setCharacterStream() throws SQLException
{
checkFreed();
initialize();
_stringWriter = new StringWriter();
return _stringWriter;
}
public synchronized Result setResult(Class resultClass) throws SQLException
{
checkFreed();
initialize();
if (resultClass == null || DOMResult.class.equals(resultClass)) {
_domResult = new DOMResult();
_active = true;
return _domResult;
} else if (SAXResult.class.equals(resultClass)) {
try {
SAXTransformerFactory transformerFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
TransformerHandler transformerHandler = transformerFactory.newTransformerHandler();
_stringWriter = new StringWriter();
transformerHandler.setResult(new StreamResult(_stringWriter));
_active = true;
return new SAXResult(transformerHandler);
} catch (TransformerException te) {
throw new PSQLException(GT.tr("Unable to create SAXResult for SQLXML."), PSQLState.UNEXPECTED_ERROR, te);
}
} else if (StreamResult.class.equals(resultClass)) {
_stringWriter = new StringWriter();
_active = true;
return new StreamResult(_stringWriter);
} else if (StAXResult.class.equals(resultClass)) {
_stringWriter = new StringWriter();
try {
XMLOutputFactory xof = XMLOutputFactory.newInstance();
XMLStreamWriter xsw = xof.createXMLStreamWriter(_stringWriter);
_active = true;
return new StAXResult(xsw);
} catch (XMLStreamException xse) {
throw new PSQLException(GT.tr("Unable to create StAXResult for SQLXML"), PSQLState.UNEXPECTED_ERROR, xse);
}
}
throw new PSQLException(GT.tr("Unknown XML Result class: {0}", resultClass), PSQLState.INVALID_PARAMETER_TYPE);
}
public synchronized void setString(String value) throws SQLException
{
checkFreed();
initialize();
_data = value;
}
private void checkFreed() throws SQLException
{
if (_freed) {
throw new PSQLException(GT.tr("This SQLXML object has already been freed."), PSQLState.OBJECT_NOT_IN_STATE);
}
}
private void ensureInitialized() throws SQLException
{
if (!_initialized) {
throw new PSQLException(GT.tr("This SQLXML object has not been initialized, so you cannot retrieve data from it."), PSQLState.OBJECT_NOT_IN_STATE);
}
// Is anyone loading data into us at the moment?
if (!_active)
return;
if (_byteArrayOutputStream != null) {
try {
_data = _conn.getEncoding().decode(_byteArrayOutputStream.toByteArray());
} catch (IOException ioe) {
throw new PSQLException(GT.tr("Failed to convert binary xml data to encoding: {0}.", _conn.getEncoding().name()), PSQLState.DATA_ERROR, ioe);
} finally {
_byteArrayOutputStream = null;
_active = false;
}
} else if (_stringWriter != null) {
// This is also handling the work for Stream, SAX, and StAX Results
// as they will use the same underlying stringwriter variable.
//
_data = _stringWriter.toString();
_stringWriter = null;
_active = false;
} else if (_domResult != null) {
// Copy the content from the result to a source
// and use the identify transform to get it into a
// friendlier result format.
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
DOMSource domSource = new DOMSource(_domResult.getNode());
StringWriter stringWriter = new StringWriter();
StreamResult streamResult = new StreamResult(stringWriter);
transformer.transform(domSource, streamResult);
_data = stringWriter.toString();
} catch (TransformerException te) {
throw new PSQLException(GT.tr("Unable to convert DOMResult SQLXML data to a string."), PSQLState.DATA_ERROR, te);
}
finally {
_domResult = null;
_active = false;
}
}
}
private void initialize() throws SQLException
{
if (_initialized) {
throw new PSQLException(GT.tr("This SQLXML object has already been initialized, so you cannot manipulate it further."), PSQLState.OBJECT_NOT_IN_STATE);
}
_initialized = true;
}
// Don't clutter System.err with errors the user can't silence.
// If something bad really happens an exception will be thrown.
static class NonPrintingErrorHandler implements ErrorHandler
{
public void error(SAXParseException e) { }
public void fatalError(SAXParseException e) { }
public void warning(SAXParseException e) { }
}
}
|