001: /*
002: * Copyright 2002-2005 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: * http://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:
017: package org.springframework.orm.hibernate3.support;
018:
019: import java.io.ByteArrayInputStream;
020: import java.io.ByteArrayOutputStream;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.ObjectInputStream;
024: import java.io.ObjectOutputStream;
025: import java.io.Serializable;
026: import java.sql.PreparedStatement;
027: import java.sql.ResultSet;
028: import java.sql.SQLException;
029: import java.sql.Types;
030:
031: import javax.transaction.TransactionManager;
032:
033: import org.hibernate.HibernateException;
034:
035: import org.springframework.jdbc.support.lob.LobCreator;
036: import org.springframework.jdbc.support.lob.LobHandler;
037:
038: /**
039: * Hibernate UserType implementation for arbitrary objects that get serialized to BLOBs.
040: * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
041: *
042: * <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
043: * work with most JDBC-compliant database drivers. In this case, the field type
044: * does not have to be BLOB: For databases like MySQL and MS SQL Server, any
045: * large enough binary type will work.
046: *
047: * @author Juergen Hoeller
048: * @since 1.2
049: * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
050: */
051: public class BlobSerializableType extends AbstractLobType {
052:
053: /**
054: * Initial size for ByteArrayOutputStreams used for serialization output.
055: * <p>If a serialized object is larger than these 1024 bytes, the size of
056: * the byte array used by the output stream will be doubled each time the
057: * limit is reached.
058: */
059: private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 1024;
060:
061: /**
062: * Constructor used by Hibernate: fetches config-time LobHandler and
063: * config-time JTA TransactionManager from LocalSessionFactoryBean.
064: * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
065: * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
066: */
067: public BlobSerializableType() {
068: super ();
069: }
070:
071: /**
072: * Constructor used for testing: takes an explicit LobHandler
073: * and an explicit JTA TransactionManager (can be <code>null</code>).
074: */
075: protected BlobSerializableType(LobHandler lobHandler,
076: TransactionManager jtaTransactionManager) {
077: super (lobHandler, jtaTransactionManager);
078: }
079:
080: public int[] sqlTypes() {
081: return new int[] { Types.BLOB };
082: }
083:
084: public Class returnedClass() {
085: return Serializable.class;
086: }
087:
088: public boolean isMutable() {
089: return true;
090: }
091:
092: public Object deepCopy(Object value) throws HibernateException {
093: try {
094: // Write to new byte array to clone.
095: ByteArrayOutputStream baos = new ByteArrayOutputStream(
096: OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
097: ObjectOutputStream oos = new ObjectOutputStream(baos);
098: try {
099: oos.writeObject(value);
100: } finally {
101: oos.close();
102: }
103:
104: // Read it back and return a true copy.
105: ByteArrayInputStream bais = new ByteArrayInputStream(baos
106: .toByteArray());
107: ObjectInputStream ois = new ObjectInputStream(bais);
108: try {
109: return ois.readObject();
110: } finally {
111: ois.close();
112: }
113: } catch (ClassNotFoundException ex) {
114: throw new HibernateException(
115: "Couldn't clone BLOB contents", ex);
116: } catch (IOException ex) {
117: throw new HibernateException(
118: "Couldn't clone BLOB contents", ex);
119: }
120: }
121:
122: protected Object nullSafeGetInternal(ResultSet rs, String[] names,
123: Object owner, LobHandler lobHandler) throws SQLException,
124: IOException, HibernateException {
125:
126: InputStream is = lobHandler.getBlobAsBinaryStream(rs, names[0]);
127: if (is != null) {
128: ObjectInputStream ois = new ObjectInputStream(is);
129: try {
130: return ois.readObject();
131: } catch (ClassNotFoundException ex) {
132: throw new HibernateException(
133: "Could not deserialize BLOB contents", ex);
134: } finally {
135: ois.close();
136: }
137: } else {
138: return null;
139: }
140: }
141:
142: protected void nullSafeSetInternal(PreparedStatement ps, int index,
143: Object value, LobCreator lobCreator) throws SQLException,
144: IOException {
145:
146: if (value != null) {
147: ByteArrayOutputStream baos = new ByteArrayOutputStream(
148: OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
149: ObjectOutputStream oos = new ObjectOutputStream(baos);
150: try {
151: oos.writeObject(value);
152: oos.flush();
153: lobCreator
154: .setBlobAsBytes(ps, index, baos.toByteArray());
155: } finally {
156: oos.close();
157: }
158: } else {
159: lobCreator.setBlobAsBytes(ps, index, null);
160: }
161: }
162:
163: }
|