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