001/* 002 * Copyright 2002-2019 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.core.support; 018 019import java.io.IOException; 020import java.sql.ResultSet; 021import java.sql.SQLException; 022 023import org.springframework.dao.DataAccessException; 024import org.springframework.dao.EmptyResultDataAccessException; 025import org.springframework.dao.IncorrectResultSizeDataAccessException; 026import org.springframework.jdbc.LobRetrievalFailureException; 027import org.springframework.jdbc.core.ResultSetExtractor; 028import org.springframework.lang.Nullable; 029 030/** 031 * Abstract ResultSetExtractor implementation that assumes streaming of LOB data. 032 * Typically used as inner class, with access to surrounding method arguments. 033 * 034 * <p>Delegates to the {@code streamData} template method for streaming LOB 035 * content to some OutputStream, typically using a LobHandler. Converts an 036 * IOException thrown during streaming to a LobRetrievalFailureException. 037 * 038 * <p>A usage example with JdbcTemplate: 039 * 040 * <pre class="code">JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // reusable object 041 * final LobHandler lobHandler = new DefaultLobHandler(); // reusable object 042 * 043 * jdbcTemplate.query( 044 * "SELECT content FROM imagedb WHERE image_name=?", new Object[] {name}, 045 * new AbstractLobStreamingResultSetExtractor() { 046 * public void streamData(ResultSet rs) throws SQLException, IOException { 047 * FileCopyUtils.copy(lobHandler.getBlobAsBinaryStream(rs, 1), contentStream); 048 * } 049 * } 050 * );</pre> 051 * 052 * @author Juergen Hoeller 053 * @since 1.0.2 054 * @param <T> the result type 055 * @see org.springframework.jdbc.support.lob.LobHandler 056 * @see org.springframework.jdbc.LobRetrievalFailureException 057 */ 058public abstract class AbstractLobStreamingResultSetExtractor<T> implements ResultSetExtractor<T> { 059 060 /** 061 * Delegates to handleNoRowFound, handleMultipleRowsFound and streamData, 062 * according to the ResultSet state. Converts an IOException thrown by 063 * streamData to a LobRetrievalFailureException. 064 * @see #handleNoRowFound 065 * @see #handleMultipleRowsFound 066 * @see #streamData 067 * @see org.springframework.jdbc.LobRetrievalFailureException 068 */ 069 @Override 070 @Nullable 071 public final T extractData(ResultSet rs) throws SQLException, DataAccessException { 072 if (!rs.next()) { 073 handleNoRowFound(); 074 } 075 else { 076 try { 077 streamData(rs); 078 if (rs.next()) { 079 handleMultipleRowsFound(); 080 } 081 } 082 catch (IOException ex) { 083 throw new LobRetrievalFailureException("Could not stream LOB content", ex); 084 } 085 } 086 return null; 087 } 088 089 /** 090 * Handle the case where the ResultSet does not contain a row. 091 * @throws DataAccessException a corresponding exception, 092 * by default an EmptyResultDataAccessException 093 * @see org.springframework.dao.EmptyResultDataAccessException 094 */ 095 protected void handleNoRowFound() throws DataAccessException { 096 throw new EmptyResultDataAccessException( 097 "LobStreamingResultSetExtractor did not find row in database", 1); 098 } 099 100 /** 101 * Handle the case where the ResultSet contains multiple rows. 102 * @throws DataAccessException a corresponding exception, 103 * by default an IncorrectResultSizeDataAccessException 104 * @see org.springframework.dao.IncorrectResultSizeDataAccessException 105 */ 106 protected void handleMultipleRowsFound() throws DataAccessException { 107 throw new IncorrectResultSizeDataAccessException( 108 "LobStreamingResultSetExtractor found multiple rows in database", 1); 109 } 110 111 /** 112 * Stream LOB content from the given ResultSet to some OutputStream. 113 * <p>Typically used as inner class, with access to surrounding method arguments 114 * and to a LobHandler instance variable of the surrounding class. 115 * @param rs the ResultSet to take the LOB content from 116 * @throws SQLException if thrown by JDBC methods 117 * @throws IOException if thrown by stream access methods 118 * @throws DataAccessException in case of custom exceptions 119 * @see org.springframework.jdbc.support.lob.LobHandler#getBlobAsBinaryStream 120 * @see org.springframework.util.FileCopyUtils 121 */ 122 protected abstract void streamData(ResultSet rs) throws SQLException, IOException, DataAccessException; 123 124}