2
|
1 |
/*
|
7544
|
2 |
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
2
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
5506
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
2
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
5506
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
2
|
10 |
*
|
|
11 |
* This code 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 General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
5506
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
|
23 |
* questions.
|
2
|
24 |
*/
|
|
25 |
|
|
26 |
package javax.sql.rowset.serial;
|
|
27 |
|
|
28 |
import java.sql.*;
|
|
29 |
import java.io.*;
|
|
30 |
import java.lang.reflect.*;
|
|
31 |
|
|
32 |
|
|
33 |
/**
|
|
34 |
* A serialized mapping in the Java programming language of an SQL
|
|
35 |
* <code>BLOB</code> value.
|
|
36 |
* <P>
|
|
37 |
* The <code>SerialBlob</code> class provides a constructor for creating
|
|
38 |
* an instance from a <code>Blob</code> object. Note that the
|
|
39 |
* <code>Blob</code>
|
|
40 |
* object should have brought the SQL <code>BLOB</code> value's data over
|
|
41 |
* to the client before a <code>SerialBlob</code> object
|
|
42 |
* is constructed from it. The data of an SQL <code>BLOB</code> value can
|
|
43 |
* be materialized on the client as an array of bytes (using the method
|
|
44 |
* <code>Blob.getBytes</code>) or as a stream of uninterpreted bytes
|
|
45 |
* (using the method <code>Blob.getBinaryStream</code>).
|
|
46 |
* <P>
|
|
47 |
* <code>SerialBlob</code> methods make it possible to make a copy of a
|
|
48 |
* <code>SerialBlob</code> object as an array of bytes or as a stream.
|
|
49 |
* They also make it possible to locate a given pattern of bytes or a
|
|
50 |
* <code>Blob</code> object within a <code>SerialBlob</code> object
|
|
51 |
* and to update or truncate a <code>Blob</code> object.
|
|
52 |
*
|
|
53 |
* @author Jonathan Bruce
|
|
54 |
*/
|
|
55 |
public class SerialBlob implements Blob, Serializable, Cloneable {
|
|
56 |
|
|
57 |
/**
|
|
58 |
* A serialized array of uninterpreted bytes representing the
|
|
59 |
* value of this <code>SerialBlob</code> object.
|
|
60 |
* @serial
|
|
61 |
*/
|
|
62 |
private byte buf[];
|
|
63 |
|
|
64 |
/**
|
|
65 |
* The internal representation of the <code>Blob</code> object on which this
|
|
66 |
* <code>SerialBlob</code> object is based.
|
|
67 |
*/
|
|
68 |
private Blob blob;
|
|
69 |
|
|
70 |
/**
|
|
71 |
* The number of bytes in this <code>SerialBlob</code> object's
|
|
72 |
* array of bytes.
|
|
73 |
* @serial
|
|
74 |
*/
|
|
75 |
private long len;
|
|
76 |
|
|
77 |
/**
|
|
78 |
* The orginal number of bytes in this <code>SerialBlob</code> object's
|
|
79 |
* array of bytes when it was first established.
|
|
80 |
* @serial
|
|
81 |
*/
|
|
82 |
private long origLen;
|
|
83 |
|
|
84 |
/**
|
|
85 |
* Constructs a <code>SerialBlob</code> object that is a serialized version of
|
|
86 |
* the given <code>byte</code> array.
|
|
87 |
* <p>
|
|
88 |
* The new <code>SerialBlob</code> object is initialized with the data from the
|
|
89 |
* <code>byte</code> array, thus allowing disconnected <code>RowSet</code>
|
|
90 |
* objects to establish serialized <code>Blob</code> objects without
|
|
91 |
* touching the data source.
|
|
92 |
*
|
|
93 |
* @param b the <code>byte</code> array containing the data for the
|
|
94 |
* <code>Blob</code> object to be serialized
|
|
95 |
* @throws SerialException if an error occurs during serialization
|
|
96 |
* @throws SQLException if a SQL errors occurs
|
|
97 |
*/
|
|
98 |
public SerialBlob(byte[] b) throws SerialException, SQLException {
|
|
99 |
|
|
100 |
len = b.length;
|
|
101 |
buf = new byte[(int)len];
|
|
102 |
for(int i = 0; i < len; i++) {
|
|
103 |
buf[i] = b[i];
|
|
104 |
}
|
|
105 |
origLen = len;
|
|
106 |
}
|
|
107 |
|
|
108 |
|
|
109 |
/**
|
|
110 |
* Constructs a <code>SerialBlob</code> object that is a serialized
|
|
111 |
* version of the given <code>Blob</code> object.
|
|
112 |
* <P>
|
|
113 |
* The new <code>SerialBlob</code> object is initialized with the
|
|
114 |
* data from the <code>Blob</code> object; therefore, the
|
|
115 |
* <code>Blob</code> object should have previously brought the
|
|
116 |
* SQL <code>BLOB</code> value's data over to the client from
|
|
117 |
* the database. Otherwise, the new <code>SerialBlob</code> object
|
|
118 |
* will contain no data.
|
|
119 |
*
|
|
120 |
* @param blob the <code>Blob</code> object from which this
|
|
121 |
* <code>SerialBlob</code> object is to be constructed;
|
|
122 |
* cannot be null.
|
|
123 |
* @throws SerialException if an error occurs during serialization
|
|
124 |
* @throws SQLException if the <code>Blob</code> passed to this
|
|
125 |
* to this constructor is a <code>null</code>.
|
|
126 |
* @see java.sql.Blob
|
|
127 |
*/
|
|
128 |
public SerialBlob (Blob blob) throws SerialException, SQLException {
|
|
129 |
|
|
130 |
if (blob == null) {
|
|
131 |
throw new SQLException("Cannot instantiate a SerialBlob " +
|
|
132 |
"object with a null Blob object");
|
|
133 |
}
|
|
134 |
|
|
135 |
len = blob.length();
|
|
136 |
buf = blob.getBytes(1, (int)len );
|
|
137 |
this.blob = blob;
|
|
138 |
|
|
139 |
//if ( len < 10240000)
|
|
140 |
// len = 10240000;
|
|
141 |
origLen = len;
|
|
142 |
}
|
|
143 |
|
|
144 |
/**
|
|
145 |
* Copies the specified number of bytes, starting at the given
|
|
146 |
* position, from this <code>SerialBlob</code> object to
|
|
147 |
* another array of bytes.
|
|
148 |
* <P>
|
|
149 |
* Note that if the given number of bytes to be copied is larger than
|
|
150 |
* the length of this <code>SerialBlob</code> object's array of
|
|
151 |
* bytes, the given number will be shortened to the array's length.
|
|
152 |
*
|
|
153 |
* @param pos the ordinal position of the first byte in this
|
|
154 |
* <code>SerialBlob</code> object to be copied;
|
|
155 |
* numbering starts at <code>1</code>; must not be less
|
|
156 |
* than <code>1</code> and must be less than or equal
|
|
157 |
* to the length of this <code>SerialBlob</code> object
|
|
158 |
* @param length the number of bytes to be copied
|
|
159 |
* @return an array of bytes that is a copy of a region of this
|
|
160 |
* <code>SerialBlob</code> object, starting at the given
|
|
161 |
* position and containing the given number of consecutive bytes
|
|
162 |
* @throws SerialException if the given starting position is out of bounds
|
|
163 |
*/
|
|
164 |
public byte[] getBytes(long pos, int length) throws SerialException {
|
|
165 |
if (length > len) {
|
|
166 |
length = (int)len;
|
|
167 |
}
|
|
168 |
|
7544
|
169 |
if (pos < 1 || len - pos < 0 ) {
|
|
170 |
throw new SerialException("Invalid arguments: position cannot be "
|
|
171 |
+ "less than 1 or greater than the length of the SerialBlob");
|
2
|
172 |
}
|
|
173 |
|
|
174 |
pos--; // correct pos to array index
|
|
175 |
|
|
176 |
byte[] b = new byte[length];
|
|
177 |
|
|
178 |
for (int i = 0; i < length; i++) {
|
|
179 |
b[i] = this.buf[(int)pos];
|
|
180 |
pos++;
|
|
181 |
}
|
|
182 |
return b;
|
|
183 |
}
|
|
184 |
|
|
185 |
/**
|
|
186 |
* Retrieves the number of bytes in this <code>SerialBlob</code>
|
|
187 |
* object's array of bytes.
|
|
188 |
*
|
|
189 |
* @return a <code>long</code> indicating the length in bytes of this
|
|
190 |
* <code>SerialBlob</code> object's array of bytes
|
|
191 |
* @throws SerialException if an error occurs
|
|
192 |
*/
|
|
193 |
public long length() throws SerialException {
|
|
194 |
return len;
|
|
195 |
}
|
|
196 |
|
|
197 |
/**
|
|
198 |
* Returns this <code>SerialBlob</code> object as an input stream.
|
|
199 |
* Unlike the related method, <code>setBinaryStream</code>,
|
|
200 |
* a stream is produced regardless of whether the <code>SerialBlob</code>
|
|
201 |
* was created with a <code>Blob</code> object or a <code>byte</code> array.
|
|
202 |
*
|
|
203 |
* @return a <code>java.io.InputStream</code> object that contains
|
|
204 |
* this <code>SerialBlob</code> object's array of bytes
|
|
205 |
* @throws SerialException if an error occurs
|
|
206 |
* @see #setBinaryStream
|
|
207 |
*/
|
|
208 |
public java.io.InputStream getBinaryStream() throws SerialException {
|
|
209 |
InputStream stream = new ByteArrayInputStream(buf);
|
|
210 |
return (java.io.InputStream)stream;
|
|
211 |
}
|
|
212 |
|
|
213 |
/**
|
|
214 |
* Returns the position in this <code>SerialBlob</code> object where
|
|
215 |
* the given pattern of bytes begins, starting the search at the
|
|
216 |
* specified position.
|
|
217 |
*
|
|
218 |
* @param pattern the pattern of bytes for which to search
|
|
219 |
* @param start the position of the byte in this
|
|
220 |
* <code>SerialBlob</code> object from which to begin
|
|
221 |
* the search; the first position is <code>1</code>;
|
|
222 |
* must not be less than <code>1</code> nor greater than
|
|
223 |
* the length of this <code>SerialBlob</code> object
|
|
224 |
* @return the position in this <code>SerialBlob</code> object
|
|
225 |
* where the given pattern begins, starting at the specified
|
|
226 |
* position; <code>-1</code> if the pattern is not found
|
|
227 |
* or the given starting position is out of bounds; position
|
|
228 |
* numbering for the return value starts at <code>1</code>
|
|
229 |
* @throws SerialException if an error occurs when serializing the blob
|
|
230 |
* @throws SQLException if there is an error accessing the <code>BLOB</code>
|
|
231 |
* value from the database
|
|
232 |
*/
|
|
233 |
public long position(byte[] pattern, long start)
|
|
234 |
throws SerialException, SQLException {
|
|
235 |
if (start < 1 || start > len) {
|
|
236 |
return -1;
|
|
237 |
}
|
|
238 |
|
|
239 |
int pos = (int)start-1; // internally Blobs are stored as arrays.
|
|
240 |
int i = 0;
|
|
241 |
long patlen = pattern.length;
|
|
242 |
|
|
243 |
while (pos < len) {
|
|
244 |
if (pattern[i] == buf[pos]) {
|
|
245 |
if (i + 1 == patlen) {
|
|
246 |
return (pos + 1) - (patlen - 1);
|
|
247 |
}
|
|
248 |
i++; pos++; // increment pos, and i
|
|
249 |
} else if (pattern[i] != buf[pos]) {
|
|
250 |
pos++; // increment pos only
|
|
251 |
}
|
|
252 |
}
|
|
253 |
return -1; // not found
|
|
254 |
}
|
|
255 |
|
|
256 |
/**
|
|
257 |
* Returns the position in this <code>SerialBlob</code> object where
|
|
258 |
* the given <code>Blob</code> object begins, starting the search at the
|
|
259 |
* specified position.
|
|
260 |
*
|
|
261 |
* @param pattern the <code>Blob</code> object for which to search;
|
|
262 |
* @param start the position of the byte in this
|
|
263 |
* <code>SerialBlob</code> object from which to begin
|
|
264 |
* the search; the first position is <code>1</code>;
|
|
265 |
* must not be less than <code>1</code> nor greater than
|
|
266 |
* the length of this <code>SerialBlob</code> object
|
|
267 |
* @return the position in this <code>SerialBlob</code> object
|
|
268 |
* where the given <code>Blob</code> object begins, starting
|
|
269 |
* at the specified position; <code>-1</code> if the pattern is
|
|
270 |
* not found or the given starting position is out of bounds;
|
|
271 |
* position numbering for the return value starts at <code>1</code>
|
|
272 |
* @throws SerialException if an error occurs when serializing the blob
|
|
273 |
* @throws SQLException if there is an error accessing the <code>BLOB</code>
|
|
274 |
* value from the database
|
|
275 |
*/
|
|
276 |
public long position(Blob pattern, long start)
|
|
277 |
throws SerialException, SQLException {
|
|
278 |
return position(pattern.getBytes(1, (int)(pattern.length())), start);
|
|
279 |
}
|
|
280 |
|
|
281 |
/**
|
|
282 |
* Writes the given array of bytes to the <code>BLOB</code> value that
|
|
283 |
* this <code>Blob</code> object represents, starting at position
|
|
284 |
* <code>pos</code>, and returns the number of bytes written.
|
|
285 |
*
|
|
286 |
* @param pos the position in the SQL <code>BLOB</code> value at which
|
|
287 |
* to start writing. The first position is <code>1</code>;
|
|
288 |
* must not be less than <code>1</code> nor greater than
|
|
289 |
* the length of this <code>SerialBlob</code> object.
|
|
290 |
* @param bytes the array of bytes to be written to the <code>BLOB</code>
|
|
291 |
* value that this <code>Blob</code> object represents
|
|
292 |
* @return the number of bytes written
|
|
293 |
* @throws SerialException if there is an error accessing the
|
|
294 |
* <code>BLOB</code> value; or if an invalid position is set; if an
|
|
295 |
* invalid offset value is set
|
|
296 |
* @throws SQLException if there is an error accessing the <code>BLOB</code>
|
|
297 |
* value from the database
|
|
298 |
* @see #getBytes
|
|
299 |
*/
|
|
300 |
public int setBytes(long pos, byte[] bytes)
|
|
301 |
throws SerialException, SQLException {
|
|
302 |
return (setBytes(pos, bytes, 0, bytes.length));
|
|
303 |
}
|
|
304 |
|
|
305 |
/**
|
|
306 |
* Writes all or part of the given <code>byte</code> array to the
|
|
307 |
* <code>BLOB</code> value that this <code>Blob</code> object represents
|
|
308 |
* and returns the number of bytes written.
|
|
309 |
* Writing starts at position <code>pos</code> in the <code>BLOB</code>
|
|
310 |
* value; <i>len</i> bytes from the given byte array are written.
|
|
311 |
*
|
|
312 |
* @param pos the position in the <code>BLOB</code> object at which
|
|
313 |
* to start writing. The first position is <code>1</code>;
|
|
314 |
* must not be less than <code>1</code> nor greater than
|
|
315 |
* the length of this <code>SerialBlob</code> object.
|
|
316 |
* @param bytes the array of bytes to be written to the <code>BLOB</code>
|
|
317 |
* value
|
|
318 |
* @param offset the offset in the <code>byte</code> array at which
|
|
319 |
* to start reading the bytes. The first offset position is
|
|
320 |
* <code>0</code>; must not be less than <code>0</code> nor greater
|
|
321 |
* than the length of the <code>byte</code> array
|
|
322 |
* @param length the number of bytes to be written to the
|
|
323 |
* <code>BLOB</code> value from the array of bytes <i>bytes</i>.
|
|
324 |
*
|
|
325 |
* @return the number of bytes written
|
|
326 |
* @throws SerialException if there is an error accessing the
|
|
327 |
* <code>BLOB</code> value; if an invalid position is set; if an
|
|
328 |
* invalid offset value is set; if number of bytes to be written
|
|
329 |
* is greater than the <code>SerialBlob</code> length; or the combined
|
|
330 |
* values of the length and offset is greater than the Blob buffer
|
|
331 |
* @throws SQLException if there is an error accessing the <code>BLOB</code>
|
|
332 |
* value from the database.
|
|
333 |
* @see #getBytes
|
|
334 |
*/
|
|
335 |
public int setBytes(long pos, byte[] bytes, int offset, int length)
|
|
336 |
throws SerialException, SQLException {
|
|
337 |
|
|
338 |
if (offset < 0 || offset > bytes.length) {
|
|
339 |
throw new SerialException("Invalid offset in byte array set");
|
|
340 |
}
|
|
341 |
|
|
342 |
if (pos < 1 || pos > this.length()) {
|
|
343 |
throw new SerialException("Invalid position in BLOB object set");
|
|
344 |
}
|
|
345 |
|
|
346 |
if ((long)(length) > origLen) {
|
|
347 |
throw new SerialException("Buffer is not sufficient to hold the value");
|
|
348 |
}
|
|
349 |
|
|
350 |
if ((length + offset) > bytes.length) {
|
|
351 |
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
|
|
352 |
"and length that is greater that the Blob buffer");
|
|
353 |
}
|
|
354 |
|
|
355 |
int i = 0;
|
|
356 |
pos--; // correct to array indexing
|
|
357 |
while ( i < length || (offset + i +1) < (bytes.length-offset) ) {
|
|
358 |
this.buf[(int)pos + i] = bytes[offset + i ];
|
|
359 |
i++;
|
|
360 |
}
|
|
361 |
return i;
|
|
362 |
}
|
|
363 |
|
|
364 |
/**
|
|
365 |
* Retrieves a stream that can be used to write to the <code>BLOB</code>
|
|
366 |
* value that this <code>Blob</code> object represents. The stream begins
|
|
367 |
* at position <code>pos</code>. This method forwards the
|
|
368 |
* <code>setBinaryStream()</code> call to the underlying <code>Blob</code> in
|
|
369 |
* the event that this <code>SerialBlob</code> object is instantiated with a
|
|
370 |
* <code>Blob</code>. If this <code>SerialBlob</code> is instantiated with
|
|
371 |
* a <code>byte</code> array, a <code>SerialException</code> is thrown.
|
|
372 |
*
|
|
373 |
* @param pos the position in the <code>BLOB</code> value at which
|
|
374 |
* to start writing
|
|
375 |
* @return a <code>java.io.OutputStream</code> object to which data can
|
|
376 |
* be written
|
|
377 |
* @throws SQLException if there is an error accessing the
|
|
378 |
* <code>BLOB</code> value
|
|
379 |
* @throws SerialException if the SerialBlob in not instantiated with a
|
|
380 |
* <code>Blob</code> object that supports <code>setBinaryStream()</code>
|
|
381 |
* @see #getBinaryStream
|
|
382 |
*/
|
|
383 |
public java.io.OutputStream setBinaryStream(long pos)
|
|
384 |
throws SerialException, SQLException {
|
|
385 |
if (this.blob.setBinaryStream(pos) != null) {
|
|
386 |
return this.blob.setBinaryStream(pos);
|
|
387 |
} else {
|
|
388 |
throw new SerialException("Unsupported operation. SerialBlob cannot " +
|
|
389 |
"return a writable binary stream, unless instantiated with a Blob object " +
|
|
390 |
"that provides a setBinaryStream() implementation");
|
|
391 |
}
|
|
392 |
}
|
|
393 |
|
|
394 |
/**
|
|
395 |
* Truncates the <code>BLOB</code> value that this <code>Blob</code>
|
|
396 |
* object represents to be <code>len</code> bytes in length.
|
|
397 |
*
|
|
398 |
* @param length the length, in bytes, to which the <code>BLOB</code>
|
|
399 |
* value that this <code>Blob</code> object represents should be
|
|
400 |
* truncated
|
|
401 |
* @throws SerialException if there is an error accessing the Blob value;
|
|
402 |
* or the length to truncate is greater that the SerialBlob length
|
|
403 |
*/
|
|
404 |
public void truncate(long length) throws SerialException {
|
|
405 |
|
|
406 |
if (length > len) {
|
|
407 |
throw new SerialException
|
|
408 |
("Length more than what can be truncated");
|
|
409 |
} else if((int)length == 0) {
|
|
410 |
buf = new byte[0];
|
|
411 |
len = length;
|
|
412 |
} else {
|
|
413 |
len = length;
|
|
414 |
buf = this.getBytes(1, (int)len);
|
|
415 |
}
|
|
416 |
}
|
|
417 |
|
|
418 |
|
|
419 |
/**
|
|
420 |
* Returns an <code>InputStream</code> object that contains a partial <code>Blob</code> value,
|
|
421 |
* starting with the byte specified by pos, which is length bytes in length.
|
|
422 |
*
|
|
423 |
* @param pos the offset to the first byte of the partial value to be retrieved.
|
|
424 |
* The first byte in the <code>Blob</code> is at position 1
|
|
425 |
* @param length the length in bytes of the partial value to be retrieved
|
|
426 |
* @return <code>InputStream</code> through which the partial <code>Blob</code> value can be read.
|
|
427 |
* @throws SQLException if pos is less than 1 or if pos is greater than the number of bytes
|
|
428 |
* in the <code>Blob</code> or if pos + length is greater than the number of bytes
|
|
429 |
* in the <code>Blob</code>
|
|
430 |
*
|
|
431 |
* @since 1.6
|
|
432 |
*/
|
|
433 |
public InputStream getBinaryStream(long pos,long length) throws SQLException {
|
|
434 |
throw new java.lang.UnsupportedOperationException("Not supported");
|
|
435 |
}
|
|
436 |
|
|
437 |
|
|
438 |
/**
|
|
439 |
* This method frees the <code>Blob</code> object and releases the resources that it holds.
|
|
440 |
* <code>Blob</code> object. The object is invalid once the <code>free</code>
|
|
441 |
* method is called. If <code>free</code> is called multiple times, the subsequent
|
|
442 |
* calls to <code>free</code> are treated as a no-op.
|
|
443 |
*
|
|
444 |
* @throws SQLException if an error occurs releasing
|
|
445 |
* the Blob's resources
|
|
446 |
* @since 1.6
|
|
447 |
*/
|
|
448 |
public void free() throws SQLException {
|
|
449 |
throw new java.lang.UnsupportedOperationException("Not supported");
|
|
450 |
}
|
|
451 |
/**
|
|
452 |
* The identifier that assists in the serialization of this <code>SerialBlob</code>
|
|
453 |
* object.
|
|
454 |
*/
|
|
455 |
|
|
456 |
static final long serialVersionUID = -8144641928112860441L;
|
|
457 |
}
|