001/*
002 * Copyright 2002-2015 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jdbc.support.xml;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.io.Reader;
022import java.sql.PreparedStatement;
023import java.sql.ResultSet;
024import java.sql.SQLException;
025import java.sql.SQLXML;
026import javax.xml.transform.Result;
027import javax.xml.transform.Source;
028import javax.xml.transform.dom.DOMResult;
029import javax.xml.transform.dom.DOMSource;
030
031import org.w3c.dom.Document;
032
033import org.springframework.dao.DataAccessResourceFailureException;
034
035/**
036 * Default implementation of the {@link SqlXmlHandler} interface.
037 * Provides database-specific implementations for storing and
038 * retrieving XML documents to and from fields in a database,
039 * relying on the JDBC 4.0 {@code java.sql.SQLXML} facility.
040 *
041 * @author Thomas Risberg
042 * @author Juergen Hoeller
043 * @since 2.5.6
044 * @see java.sql.SQLXML
045 * @see java.sql.ResultSet#getSQLXML
046 * @see java.sql.PreparedStatement#setSQLXML
047 */
048public class Jdbc4SqlXmlHandler implements SqlXmlHandler {
049
050        //-------------------------------------------------------------------------
051        // Convenience methods for accessing XML content
052        //-------------------------------------------------------------------------
053
054        @Override
055        public String getXmlAsString(ResultSet rs, String columnName) throws SQLException {
056                SQLXML xmlObject = rs.getSQLXML(columnName);
057                return (xmlObject != null ? xmlObject.getString() : null);
058        }
059
060        @Override
061        public String getXmlAsString(ResultSet rs, int columnIndex) throws SQLException {
062                SQLXML xmlObject = rs.getSQLXML(columnIndex);
063                return (xmlObject != null ? xmlObject.getString() : null);
064        }
065
066        @Override
067        public InputStream getXmlAsBinaryStream(ResultSet rs, String columnName) throws SQLException {
068                SQLXML xmlObject = rs.getSQLXML(columnName);
069                return (xmlObject != null ? xmlObject.getBinaryStream() : null);
070        }
071
072        @Override
073        public InputStream getXmlAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException {
074                SQLXML xmlObject = rs.getSQLXML(columnIndex);
075                return (xmlObject != null ? xmlObject.getBinaryStream() : null);
076        }
077
078        @Override
079        public Reader getXmlAsCharacterStream(ResultSet rs, String columnName) throws SQLException {
080                SQLXML xmlObject = rs.getSQLXML(columnName);
081                return (xmlObject != null ? xmlObject.getCharacterStream() : null);
082        }
083
084        @Override
085        public Reader getXmlAsCharacterStream(ResultSet rs, int columnIndex) throws SQLException {
086                SQLXML xmlObject = rs.getSQLXML(columnIndex);
087                return (xmlObject != null ? xmlObject.getCharacterStream() : null);
088        }
089
090        @Override
091        public Source getXmlAsSource(ResultSet rs, String columnName, Class<? extends Source> sourceClass) throws SQLException {
092                SQLXML xmlObject = rs.getSQLXML(columnName);
093                if (xmlObject == null) {
094                        return null;
095                }
096                return (sourceClass != null ? xmlObject.getSource(sourceClass) : xmlObject.getSource(DOMSource.class));
097        }
098
099        @Override
100        public Source getXmlAsSource(ResultSet rs, int columnIndex, Class<? extends Source> sourceClass) throws SQLException {
101                SQLXML xmlObject = rs.getSQLXML(columnIndex);
102                if (xmlObject == null) {
103                        return null;
104                }
105                return (sourceClass != null ? xmlObject.getSource(sourceClass) : xmlObject.getSource(DOMSource.class));
106        }
107
108
109        //-------------------------------------------------------------------------
110        // Convenience methods for building XML content
111        //-------------------------------------------------------------------------
112
113        @Override
114        public SqlXmlValue newSqlXmlValue(final String value) {
115                return new AbstractJdbc4SqlXmlValue() {
116                        @Override
117                        protected void provideXml(SQLXML xmlObject) throws SQLException, IOException {
118                                xmlObject.setString(value);
119                        }
120                };
121        }
122
123        @Override
124        public SqlXmlValue newSqlXmlValue(final XmlBinaryStreamProvider provider) {
125                return new AbstractJdbc4SqlXmlValue() {
126                        @Override
127                        protected void provideXml(SQLXML xmlObject) throws SQLException, IOException {
128                                provider.provideXml(xmlObject.setBinaryStream());
129                        }
130                };
131        }
132
133        @Override
134        public SqlXmlValue newSqlXmlValue(final XmlCharacterStreamProvider provider) {
135                return new AbstractJdbc4SqlXmlValue() {
136                        @Override
137                        protected void provideXml(SQLXML xmlObject) throws SQLException, IOException {
138                                provider.provideXml(xmlObject.setCharacterStream());
139                        }
140                };
141        }
142
143        @Override
144        public SqlXmlValue newSqlXmlValue(final Class<? extends Result> resultClass, final XmlResultProvider provider) {
145                return new AbstractJdbc4SqlXmlValue() {
146                        @Override
147                        protected void provideXml(SQLXML xmlObject) throws SQLException, IOException {
148                                provider.provideXml(xmlObject.setResult(resultClass));
149                        }
150                };
151        }
152
153        @Override
154        public SqlXmlValue newSqlXmlValue(final Document document) {
155                return new AbstractJdbc4SqlXmlValue() {
156                        @Override
157                        protected void provideXml(SQLXML xmlObject) throws SQLException, IOException {
158                                xmlObject.setResult(DOMResult.class).setNode(document);
159                        }
160                };
161        }
162
163
164        /**
165         * Internal base class for {@link SqlXmlValue} implementations.
166         */
167        private static abstract class AbstractJdbc4SqlXmlValue implements SqlXmlValue {
168
169                private SQLXML xmlObject;
170
171                @Override
172                public void setValue(PreparedStatement ps, int paramIndex) throws SQLException {
173                        this.xmlObject = ps.getConnection().createSQLXML();
174                        try {
175                                provideXml(this.xmlObject);
176                        }
177                        catch (IOException ex) {
178                                throw new DataAccessResourceFailureException("Failure encountered while providing XML", ex);
179                        }
180                        ps.setSQLXML(paramIndex, this.xmlObject);
181                }
182
183                @Override
184                public void cleanup() {
185                        try {
186                                this.xmlObject.free();
187                        }
188                        catch (SQLException ex) {
189                                throw new DataAccessResourceFailureException("Could not free SQLXML object", ex);
190                        }
191                }
192
193                protected abstract void provideXml(SQLXML xmlObject) throws SQLException, IOException;
194        }
195
196}