001/* 002 * Copyright 2002-2017 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; 026 027import javax.xml.transform.Result; 028import javax.xml.transform.Source; 029import javax.xml.transform.dom.DOMResult; 030import javax.xml.transform.dom.DOMSource; 031 032import org.w3c.dom.Document; 033 034import org.springframework.dao.DataAccessResourceFailureException; 035import org.springframework.lang.Nullable; 036 037/** 038 * Default implementation of the {@link SqlXmlHandler} interface. 039 * Provides database-specific implementations for storing and 040 * retrieving XML documents to and from fields in a database, 041 * relying on the JDBC 4.0 {@code java.sql.SQLXML} facility. 042 * 043 * @author Thomas Risberg 044 * @author Juergen Hoeller 045 * @since 2.5.6 046 * @see java.sql.SQLXML 047 * @see java.sql.ResultSet#getSQLXML 048 * @see java.sql.PreparedStatement#setSQLXML 049 */ 050public class Jdbc4SqlXmlHandler implements SqlXmlHandler { 051 052 //------------------------------------------------------------------------- 053 // Convenience methods for accessing XML content 054 //------------------------------------------------------------------------- 055 056 @Override 057 @Nullable 058 public String getXmlAsString(ResultSet rs, String columnName) throws SQLException { 059 SQLXML xmlObject = rs.getSQLXML(columnName); 060 return (xmlObject != null ? xmlObject.getString() : null); 061 } 062 063 @Override 064 @Nullable 065 public String getXmlAsString(ResultSet rs, int columnIndex) throws SQLException { 066 SQLXML xmlObject = rs.getSQLXML(columnIndex); 067 return (xmlObject != null ? xmlObject.getString() : null); 068 } 069 070 @Override 071 @Nullable 072 public InputStream getXmlAsBinaryStream(ResultSet rs, String columnName) throws SQLException { 073 SQLXML xmlObject = rs.getSQLXML(columnName); 074 return (xmlObject != null ? xmlObject.getBinaryStream() : null); 075 } 076 077 @Override 078 @Nullable 079 public InputStream getXmlAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException { 080 SQLXML xmlObject = rs.getSQLXML(columnIndex); 081 return (xmlObject != null ? xmlObject.getBinaryStream() : null); 082 } 083 084 @Override 085 @Nullable 086 public Reader getXmlAsCharacterStream(ResultSet rs, String columnName) throws SQLException { 087 SQLXML xmlObject = rs.getSQLXML(columnName); 088 return (xmlObject != null ? xmlObject.getCharacterStream() : null); 089 } 090 091 @Override 092 @Nullable 093 public Reader getXmlAsCharacterStream(ResultSet rs, int columnIndex) throws SQLException { 094 SQLXML xmlObject = rs.getSQLXML(columnIndex); 095 return (xmlObject != null ? xmlObject.getCharacterStream() : null); 096 } 097 098 @Override 099 @Nullable 100 public Source getXmlAsSource(ResultSet rs, String columnName, @Nullable Class<? extends Source> sourceClass) 101 throws SQLException { 102 103 SQLXML xmlObject = rs.getSQLXML(columnName); 104 if (xmlObject == null) { 105 return null; 106 } 107 return (sourceClass != null ? xmlObject.getSource(sourceClass) : xmlObject.getSource(DOMSource.class)); 108 } 109 110 @Override 111 @Nullable 112 public Source getXmlAsSource(ResultSet rs, int columnIndex, @Nullable Class<? extends Source> sourceClass) 113 throws SQLException { 114 115 SQLXML xmlObject = rs.getSQLXML(columnIndex); 116 if (xmlObject == null) { 117 return null; 118 } 119 return (sourceClass != null ? xmlObject.getSource(sourceClass) : xmlObject.getSource(DOMSource.class)); 120 } 121 122 123 //------------------------------------------------------------------------- 124 // Convenience methods for building XML content 125 //------------------------------------------------------------------------- 126 127 @Override 128 public SqlXmlValue newSqlXmlValue(final String value) { 129 return new AbstractJdbc4SqlXmlValue() { 130 @Override 131 protected void provideXml(SQLXML xmlObject) throws SQLException, IOException { 132 xmlObject.setString(value); 133 } 134 }; 135 } 136 137 @Override 138 public SqlXmlValue newSqlXmlValue(final XmlBinaryStreamProvider provider) { 139 return new AbstractJdbc4SqlXmlValue() { 140 @Override 141 protected void provideXml(SQLXML xmlObject) throws SQLException, IOException { 142 provider.provideXml(xmlObject.setBinaryStream()); 143 } 144 }; 145 } 146 147 @Override 148 public SqlXmlValue newSqlXmlValue(final XmlCharacterStreamProvider provider) { 149 return new AbstractJdbc4SqlXmlValue() { 150 @Override 151 protected void provideXml(SQLXML xmlObject) throws SQLException, IOException { 152 provider.provideXml(xmlObject.setCharacterStream()); 153 } 154 }; 155 } 156 157 @Override 158 public SqlXmlValue newSqlXmlValue(final Class<? extends Result> resultClass, final XmlResultProvider provider) { 159 return new AbstractJdbc4SqlXmlValue() { 160 @Override 161 protected void provideXml(SQLXML xmlObject) throws SQLException, IOException { 162 provider.provideXml(xmlObject.setResult(resultClass)); 163 } 164 }; 165 } 166 167 @Override 168 public SqlXmlValue newSqlXmlValue(final Document document) { 169 return new AbstractJdbc4SqlXmlValue() { 170 @Override 171 protected void provideXml(SQLXML xmlObject) throws SQLException, IOException { 172 xmlObject.setResult(DOMResult.class).setNode(document); 173 } 174 }; 175 } 176 177 178 /** 179 * Internal base class for {@link SqlXmlValue} implementations. 180 */ 181 private abstract static class AbstractJdbc4SqlXmlValue implements SqlXmlValue { 182 183 @Nullable 184 private SQLXML xmlObject; 185 186 @Override 187 public void setValue(PreparedStatement ps, int paramIndex) throws SQLException { 188 this.xmlObject = ps.getConnection().createSQLXML(); 189 try { 190 provideXml(this.xmlObject); 191 } 192 catch (IOException ex) { 193 throw new DataAccessResourceFailureException("Failure encountered while providing XML", ex); 194 } 195 ps.setSQLXML(paramIndex, this.xmlObject); 196 } 197 198 @Override 199 public void cleanup() { 200 if (this.xmlObject != null) { 201 try { 202 this.xmlObject.free(); 203 } 204 catch (SQLException ex) { 205 throw new DataAccessResourceFailureException("Could not free SQLXML object", ex); 206 } 207 } 208 } 209 210 protected abstract void provideXml(SQLXML xmlObject) throws SQLException, IOException; 211 } 212 213}