001: //$Id: $
002: package org.hibernate.type;
003:
004: import java.sql.PreparedStatement;
005: import java.sql.SQLException;
006: import java.sql.ResultSet;
007: import java.sql.Types;
008: import java.io.ByteArrayInputStream;
009: import java.io.InputStream;
010: import java.io.ByteArrayOutputStream;
011: import java.io.IOException;
012: import java.util.Comparator;
013:
014: import org.hibernate.HibernateException;
015: import org.hibernate.EntityMode;
016: import org.hibernate.engine.SessionImplementor;
017: import org.hibernate.cfg.Environment;
018:
019: /**
020: * Logic to bind stream of byte into a VARBINARY
021: *
022: * @author Gavin King
023: * @author Emmanuel Bernard
024: */
025: public abstract class AbstractBynaryType extends MutableType implements
026: VersionType, Comparator {
027:
028: /**
029: * Convert the byte[] into the expected object type
030: */
031: abstract protected Object toExternalFormat(byte[] bytes);
032:
033: /**
034: * Convert the object into the internal byte[] representation
035: */
036: abstract protected byte[] toInternalFormat(Object bytes);
037:
038: public void set(PreparedStatement st, Object value, int index)
039: throws HibernateException, SQLException {
040: byte[] internalValue = toInternalFormat(value);
041: if (Environment.useStreamsForBinary()) {
042: st.setBinaryStream(index, new ByteArrayInputStream(
043: internalValue), internalValue.length);
044: } else {
045: st.setBytes(index, internalValue);
046: }
047: }
048:
049: public Object get(ResultSet rs, String name)
050: throws HibernateException, SQLException {
051:
052: if (Environment.useStreamsForBinary()) {
053:
054: InputStream inputStream = rs.getBinaryStream(name);
055:
056: if (inputStream == null)
057: return toExternalFormat(null); // is this really necessary?
058:
059: ByteArrayOutputStream outputStream = new ByteArrayOutputStream(
060: 2048);
061: byte[] buffer = new byte[2048];
062:
063: try {
064: while (true) {
065: int amountRead = inputStream.read(buffer);
066: if (amountRead == -1) {
067: break;
068: }
069: outputStream.write(buffer, 0, amountRead);
070: }
071:
072: inputStream.close();
073: outputStream.close();
074: } catch (IOException ioe) {
075: throw new HibernateException(
076: "IOException occurred reading a binary value",
077: ioe);
078: }
079:
080: return toExternalFormat(outputStream.toByteArray());
081:
082: } else {
083: return toExternalFormat(rs.getBytes(name));
084: }
085: }
086:
087: public int sqlType() {
088: return Types.VARBINARY;
089: }
090:
091: // VersionType impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
092: // Note : simply returns null for seed() and next() as the only known
093: // application of binary types for versioning is for use with the
094: // TIMESTAMP datatype supported by Sybase and SQL Server, which
095: // are completely db-generated values...
096: public Object seed(SessionImplementor session) {
097: return null;
098: }
099:
100: public Object next(Object current, SessionImplementor session) {
101: return current;
102: }
103:
104: public Comparator getComparator() {
105: return this ;
106: }
107:
108: public int compare(Object o1, Object o2) {
109: return compare(o1, o2, null);
110: }
111:
112: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113:
114: public boolean isEqual(Object x, Object y) {
115: return x == y
116: || (x != null && y != null && java.util.Arrays.equals(
117: toInternalFormat(x), toInternalFormat(y)));
118: }
119:
120: public int getHashCode(Object x, EntityMode entityMode) {
121: byte[] bytes = toInternalFormat(x);
122: int hashCode = 1;
123: for (int j = 0; j < bytes.length; j++) {
124: hashCode = 31 * hashCode + bytes[j];
125: }
126: return hashCode;
127: }
128:
129: public int compare(Object x, Object y, EntityMode entityMode) {
130: byte[] xbytes = toInternalFormat(x);
131: byte[] ybytes = toInternalFormat(y);
132: if (xbytes.length < ybytes.length)
133: return -1;
134: if (xbytes.length > ybytes.length)
135: return 1;
136: for (int i = 0; i < xbytes.length; i++) {
137: if (xbytes[i] < ybytes[i])
138: return -1;
139: if (xbytes[i] > ybytes[i])
140: return 1;
141: }
142: return 0;
143: }
144:
145: public abstract String getName();
146:
147: public String toString(Object val) {
148: byte[] bytes = toInternalFormat(val);
149: StringBuffer buf = new StringBuffer();
150: for (int i = 0; i < bytes.length; i++) {
151: String hexStr = Integer.toHexString(bytes[i]
152: - Byte.MIN_VALUE);
153: if (hexStr.length() == 1)
154: buf.append('0');
155: buf.append(hexStr);
156: }
157: return buf.toString();
158: }
159:
160: public Object deepCopyNotNull(Object value) {
161: byte[] bytes = toInternalFormat(value);
162: byte[] result = new byte[bytes.length];
163: System.arraycopy(bytes, 0, result, 0, bytes.length);
164: return toExternalFormat(result);
165: }
166:
167: public Object fromStringValue(String xml) throws HibernateException {
168: if (xml == null)
169: return null;
170: if (xml.length() % 2 != 0)
171: throw new IllegalArgumentException(
172: "The string is not a valid xml representation of a binary content.");
173: byte[] bytes = new byte[xml.length() / 2];
174: for (int i = 0; i < bytes.length; i++) {
175: String hexStr = xml.substring(i * 2, (i + 1) * 2);
176: bytes[i] = (byte) (Integer.parseInt(hexStr, 16) + Byte.MIN_VALUE);
177: }
178: return toExternalFormat(bytes);
179: }
180:
181: }
|