001/*
002 * Copyright 2002-2018 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.lob;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.io.Reader;
022import java.sql.Blob;
023import java.sql.Clob;
024import java.sql.PreparedStatement;
025import java.sql.SQLException;
026import java.util.LinkedHashSet;
027import java.util.Set;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031
032import org.springframework.dao.DataAccessResourceFailureException;
033import org.springframework.util.FileCopyUtils;
034
035/**
036 * {@link LobCreator} implementation based on temporary LOBs,
037 * using JDBC 4.0's {@link java.sql.Connection#createBlob()} /
038 * {@link java.sql.Connection#createClob()} mechanism.
039 *
040 * <p>Used by DefaultLobHandler's {@link DefaultLobHandler#setCreateTemporaryLob} mode.
041 * Can also be used directly to reuse the tracking and freeing of temporary LOBs.
042 *
043 * @author Juergen Hoeller
044 * @since 3.2.2
045 * @see DefaultLobHandler#setCreateTemporaryLob
046 * @see java.sql.Connection#createBlob()
047 * @see java.sql.Connection#createClob()
048 */
049public class TemporaryLobCreator implements LobCreator {
050
051        protected static final Log logger = LogFactory.getLog(TemporaryLobCreator.class);
052
053        private final Set<Blob> temporaryBlobs = new LinkedHashSet<Blob>(1);
054
055        private final Set<Clob> temporaryClobs = new LinkedHashSet<Clob>(1);
056
057
058        @Override
059        public void setBlobAsBytes(PreparedStatement ps, int paramIndex, byte[] content)
060                        throws SQLException {
061
062                if (content != null) {
063                        Blob blob = ps.getConnection().createBlob();
064                        blob.setBytes(1, content);
065                        this.temporaryBlobs.add(blob);
066                        ps.setBlob(paramIndex, blob);
067                }
068                else {
069                        ps.setBlob(paramIndex, (Blob) null);
070                }
071
072                if (logger.isDebugEnabled()) {
073                        logger.debug(content != null ? "Copied bytes into temporary BLOB with length " + content.length :
074                                        "Set BLOB to null");
075                }
076        }
077
078        @Override
079        public void setBlobAsBinaryStream(
080                        PreparedStatement ps, int paramIndex, InputStream binaryStream, int contentLength)
081                        throws SQLException {
082
083                if (binaryStream != null) {
084                        Blob blob = ps.getConnection().createBlob();
085                        try {
086                                FileCopyUtils.copy(binaryStream, blob.setBinaryStream(1));
087                        }
088                        catch (IOException ex) {
089                                throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
090                        }
091                        this.temporaryBlobs.add(blob);
092                        ps.setBlob(paramIndex, blob);
093                }
094                else {
095                        ps.setBlob(paramIndex, (Blob) null);
096                }
097
098                if (logger.isDebugEnabled()) {
099                        logger.debug(binaryStream != null ?
100                                        "Copied binary stream into temporary BLOB with length " + contentLength :
101                                        "Set BLOB to null");
102                }
103        }
104
105        @Override
106        public void setClobAsString(PreparedStatement ps, int paramIndex, String content)
107                        throws SQLException {
108
109                if (content != null) {
110                        Clob clob = ps.getConnection().createClob();
111                        clob.setString(1, content);
112                        this.temporaryClobs.add(clob);
113                        ps.setClob(paramIndex, clob);
114                }
115                else {
116                        ps.setClob(paramIndex, (Clob) null);
117                }
118
119                if (logger.isDebugEnabled()) {
120                        logger.debug(content != null ? "Copied string into temporary CLOB with length " + content.length() :
121                                        "Set CLOB to null");
122                }
123        }
124
125        @Override
126        public void setClobAsAsciiStream(
127                        PreparedStatement ps, int paramIndex, InputStream asciiStream, int contentLength)
128                        throws SQLException {
129
130                if (asciiStream != null) {
131                        Clob clob = ps.getConnection().createClob();
132                        try {
133                                FileCopyUtils.copy(asciiStream, clob.setAsciiStream(1));
134                        }
135                        catch (IOException ex) {
136                                throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
137                        }
138                        this.temporaryClobs.add(clob);
139                        ps.setClob(paramIndex, clob);
140                }
141                else {
142                        ps.setClob(paramIndex, (Clob) null);
143                }
144
145                if (logger.isDebugEnabled()) {
146                        logger.debug(asciiStream != null ?
147                                        "Copied ASCII stream into temporary CLOB with length " + contentLength :
148                                        "Set CLOB to null");
149                }
150        }
151
152        @Override
153        public void setClobAsCharacterStream(
154                        PreparedStatement ps, int paramIndex, Reader characterStream, int contentLength)
155                        throws SQLException {
156
157                if (characterStream != null) {
158                        Clob clob = ps.getConnection().createClob();
159                        try {
160                                FileCopyUtils.copy(characterStream, clob.setCharacterStream(1));
161                        }
162                        catch (IOException ex) {
163                                throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
164                        }
165                        this.temporaryClobs.add(clob);
166                        ps.setClob(paramIndex, clob);
167                }
168                else {
169                        ps.setClob(paramIndex, (Clob) null);
170                }
171
172                if (logger.isDebugEnabled()) {
173                        logger.debug(characterStream != null ?
174                                        "Copied character stream into temporary CLOB with length " + contentLength :
175                                        "Set CLOB to null");
176                }
177        }
178
179        @Override
180        public void close() {
181                try {
182                        for (Blob blob : this.temporaryBlobs) {
183                                blob.free();
184                        }
185                        for (Clob clob : this.temporaryClobs) {
186                                clob.free();
187                        }
188                }
189                catch (SQLException ex) {
190                        logger.error("Could not free LOBs", ex);
191                }
192        }
193
194}