KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > driver > Blob


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2005 Emic Networks
4  * Contact: c-jdbc@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation; either version 2.1 of the License, or any later
9  * version.
10  *
11  * This library is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19  *
20  * Initial developer(s): Marc Herbert
21  * Contributor(s): ______________________.
22  */

23
24 package org.objectweb.cjdbc.driver;
25
26 import java.io.ByteArrayInputStream JavaDoc;
27 import java.io.Serializable JavaDoc;
28 import java.sql.SQLException JavaDoc;
29
30 import org.objectweb.cjdbc.common.exceptions.NotImplementedException;
31 import org.objectweb.cjdbc.common.exceptions.driver.DriverSQLException;
32
33 /**
34  * The representation (mapping) in the Java <sup><small>TM </small> </sup>
35  * programming language of an SQL <code>BLOB</code> value. By default drivers
36  * implement <code>Blob</code> using an SQL <code>locator(BLOB)</code>,
37  * which means that a <code>Blob</code> object contains a logical pointer to
38  * the SQL <code>BLOB</code> data rather than the data itself. But since this
39  * is highly database-specific, we are unable to do that and implement Blobs
40  * using a simple private byte array copy instead. This may consume a lot of
41  * memory but this is both portable across databases and even legal from a JDBC
42  * standard point of view as long as our method
43  * {@link org.objectweb.cjdbc.driver.DatabaseMetaData#locatorsUpdateCopy()}
44  * returns true.
45  *
46  * @see java.sql.Blob
47  * @author <a HREF="mailto:Marc.Herbert@emicnetworks.com">Marc Herbert </a>
48  * @since JDK 1.2
49  */

50 public class Blob implements java.sql.Blob JavaDoc, Serializable JavaDoc
51 {
52   /** The binary data that makes up this <code>BLOB</code>. */
53   byte[] internalArray;
54
55
56   // ------------- JDBC 2.1 / JDK 1.2-------------------
57

58   /**
59    * @see java.sql.Blob#length()
60    */

61   public long length() throws SQLException JavaDoc
62   {
63     checkInitialized();
64     return internalArray.length;
65   }
66
67   /**
68    * @see java.sql.Blob#getBytes(long, int)
69    */

70   public byte[] getBytes(long sqlPos, int length) throws SQLException JavaDoc
71   {
72     checkInitialized();
73     checkSQLRangeIsSupported(sqlPos, length);
74
75     int arrayPos = (int) (sqlPos - 1);
76     return resizedByteArray(internalArray, arrayPos, //
77
Math.min(length, // no more than asked for
78
internalArray.length - arrayPos)); // no more than what we have
79
}
80
81   /**
82    * @see java.sql.Blob#getBinaryStream()
83    */

84   public java.io.InputStream JavaDoc getBinaryStream() throws SQLException JavaDoc
85   {
86     checkInitialized();
87     return new ByteArrayInputStream JavaDoc(internalArray);
88   }
89
90   /**
91    * @see java.sql.Blob#position(byte[], long)
92    */

93   public long position(byte[] pattern, long sqlStart) throws SQLException JavaDoc
94   {
95     checkInitialized();
96     checkSQLRangeIsSupported(sqlStart, 0);
97
98     throw new NotImplementedException("position not yet implemented");
99   }
100
101   /**
102    * @see java.sql.Blob#position(java.sql.Blob, long)
103    */

104   public long position(java.sql.Blob JavaDoc pattern, long sqlStart)
105       throws SQLException JavaDoc
106   {
107     checkInitialized();
108     checkSQLRangeIsSupported(sqlStart, 0);
109
110     // FIXME: implement me
111
return position(pattern.getBytes(0, (int) pattern.length()), sqlStart);
112   }
113
114   // ------------- JDBC 3.0 / JDK 1.4-------------------
115

116   /**
117    * @see java.sql.Blob#setBytes(long, byte[], int, int)
118    */

119   public int setBytes(long sqlStartPos, byte[] srcArray) throws SQLException JavaDoc
120   {
121     return this.setBytes(sqlStartPos, srcArray, 0, srcArray.length);
122   }
123
124   /**
125    * @see java.sql.Blob#setBytes(long, byte[], int, int)
126    */

127   public int setBytes(long sqlStartPos, byte[] srcArray, int srcArrayOffset,
128       int copiedLength) throws SQLException JavaDoc
129   {
130     checkInitialized();
131     checkSQLRangeIsSupported(sqlStartPos, copiedLength);
132
133     int minimumLengthNeeded = (int) (sqlStartPos - 1) + copiedLength;
134
135     // If we are too small, let's extend ourselves
136
// FIXME: do the specs say we should do this?
137
if (this.length() < minimumLengthNeeded)
138       internalArray = resizedByteArray(internalArray, 0, minimumLengthNeeded);
139
140     // else FIXME: when we are "longer", should we remove our tail or keep
141
// it? Do the specs say something about this? Let's keep the tail for now.
142

143     // Finally copy argument to ourselves.
144
// Bytes between binaryData.length and pos-1 will stay to zero....
145
// FIXME: do the specs say something about this?
146
System.arraycopy(srcArray, srcArrayOffset, internalArray,
147         (int) (sqlStartPos - 1), copiedLength);
148
149     /*
150      * huh, what else ? OK, something else would make sense in case we don't
151      * extend the array.
152      */

153     return copiedLength;
154   }
155
156   /**
157    * @see java.sql.Blob#setBinaryStream(long)
158    */

159   public java.io.OutputStream JavaDoc setBinaryStream(long sqlStart)
160       throws SQLException JavaDoc
161   {
162     checkInitialized();
163     checkSQLRangeIsSupported(sqlStart, 0);
164
165     return new BlobOutputStream(this, (int) (sqlStart - 1));
166   }
167
168   /**
169    * @see java.sql.Blob#truncate(long)
170    */

171   public void truncate(long newLen) throws SQLException JavaDoc
172   {
173     checkInitialized();
174
175     if (newLen >= this.length())
176       return;
177
178     internalArray = resizedByteArray(internalArray, 0, (int) newLen);
179   }
180
181   // ----------- JDBC 4.0 --------------
182
/**
183    * This method frees the Blob object and releases the resources that it holds.
184    */

185   public void free()
186   {
187     internalArray = null;
188   }
189
190   // ------------------ BLOB internals ------------
191

192   /**
193    * Creates a new <code>Blob</code> object built from a copy of the given
194    * byte array.
195    *
196    * @param src the array to copy
197    */

198   public Blob(byte[] src)
199   {
200     // just clone the array
201
this.internalArray = resizedByteArray(src, 0, src.length);
202   }
203
204   /**
205    * BlobOutputStream needs it
206    */

207   byte[] getInternalByteArray()
208   {
209     return internalArray;
210   }
211
212   private void checkInitialized() throws DriverSQLException
213   {
214     if (null == internalArray)
215       throw new DriverSQLException("Blob has been freed");
216   }
217
218   /**
219    * Checks that indexes (sqlStart) and (sqlStart+len) are correct. Valid
220    * sqlStart begins at 1 (SQL-style). A reasonable sqlEnd of Blob is no more
221    * than Integer.MAX_VALUE+1 because we implement using Java arrays. This
222    * method is basically a check to use before casting from long to int.
223    *
224    * @param sqlStart start index
225    * @param len length
226    * @throws SQLException
227    */

228   private static void checkSQLRangeIsSupported(long sqlStart, int len)
229       throws SQLException JavaDoc
230   {
231     long arrayStart = sqlStart - 1;
232     if (arrayStart < 0)
233     {
234       throw new DriverSQLException("Illegal argument: start of Blob ("
235           + sqlStart + ") cannot be less than 1");
236     }
237     if (Integer.MAX_VALUE <= arrayStart + len)
238     {
239       throw new NotImplementedException("End of Blob (" + (sqlStart + len)
240           + ") is too great. Blobs greater than " + Integer.MAX_VALUE
241           + " are not supported");
242     }
243   }
244
245   /**
246    * Returns a copy of the byte array argument starting at srcFrom and extended
247    * or shortened to newLength. srcFrom index starts from zero (regular style).
248    * <p>
249    * This roughly double the memory used... *sigh*
250    * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4655503 is tagged
251    * "fixed" but nothing changed ?!
252    */

253   private byte[] resizedByteArray(byte[] src, int srcStart, int newSize)
254   {
255     byte[] newArray = new byte[newSize];
256     System.arraycopy(src, srcStart, newArray, 0, Math.min(
257         src.length - srcStart, // don't pass the old size
258
newSize)); // don't pass the new size
259
return newArray;
260   }
261
262 }
Popular Tags