Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/sql/rowset/serial/SerialBlob.java
38918 views
1
/*
2
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
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
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
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
*
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.
24
*/
25
26
package javax.sql.rowset.serial;
27
28
import java.sql.*;
29
import java.io.*;
30
import java.lang.reflect.*;
31
import java.util.Arrays;
32
33
34
/**
35
* A serialized mapping in the Java programming language of an SQL
36
* <code>BLOB</code> value.
37
* <P>
38
* The <code>SerialBlob</code> class provides a constructor for creating
39
* an instance from a <code>Blob</code> object. Note that the
40
* <code>Blob</code>
41
* object should have brought the SQL <code>BLOB</code> value's data over
42
* to the client before a <code>SerialBlob</code> object
43
* is constructed from it. The data of an SQL <code>BLOB</code> value can
44
* be materialized on the client as an array of bytes (using the method
45
* <code>Blob.getBytes</code>) or as a stream of uninterpreted bytes
46
* (using the method <code>Blob.getBinaryStream</code>).
47
* <P>
48
* <code>SerialBlob</code> methods make it possible to make a copy of a
49
* <code>SerialBlob</code> object as an array of bytes or as a stream.
50
* They also make it possible to locate a given pattern of bytes or a
51
* <code>Blob</code> object within a <code>SerialBlob</code> object
52
* and to update or truncate a <code>Blob</code> object.
53
*
54
* <h3> Thread safety </h3>
55
*
56
* <p> A SerialBlob is not safe for use by multiple concurrent threads. If a
57
* SerialBlob is to be used by more than one thread then access to the SerialBlob
58
* should be controlled by appropriate synchronization.
59
*
60
* @author Jonathan Bruce
61
*/
62
public class SerialBlob implements Blob, Serializable, Cloneable {
63
64
/**
65
* A serialized array of uninterpreted bytes representing the
66
* value of this <code>SerialBlob</code> object.
67
* @serial
68
*/
69
private byte[] buf;
70
71
/**
72
* The internal representation of the <code>Blob</code> object on which this
73
* <code>SerialBlob</code> object is based.
74
*/
75
private Blob blob;
76
77
/**
78
* The number of bytes in this <code>SerialBlob</code> object's
79
* array of bytes.
80
* @serial
81
*/
82
private long len;
83
84
/**
85
* The original number of bytes in this <code>SerialBlob</code> object's
86
* array of bytes when it was first established.
87
* @serial
88
*/
89
private long origLen;
90
91
/**
92
* Constructs a <code>SerialBlob</code> object that is a serialized version of
93
* the given <code>byte</code> array.
94
* <p>
95
* The new <code>SerialBlob</code> object is initialized with the data from the
96
* <code>byte</code> array, thus allowing disconnected <code>RowSet</code>
97
* objects to establish serialized <code>Blob</code> objects without
98
* touching the data source.
99
*
100
* @param b the <code>byte</code> array containing the data for the
101
* <code>Blob</code> object to be serialized
102
* @throws SerialException if an error occurs during serialization
103
* @throws SQLException if a SQL errors occurs
104
*/
105
public SerialBlob(byte[] b)
106
throws SerialException, SQLException {
107
108
len = b.length;
109
buf = new byte[(int)len];
110
for(int i = 0; i < len; i++) {
111
buf[i] = b[i];
112
}
113
origLen = len;
114
}
115
116
117
/**
118
* Constructs a <code>SerialBlob</code> object that is a serialized
119
* version of the given <code>Blob</code> object.
120
* <P>
121
* The new <code>SerialBlob</code> object is initialized with the
122
* data from the <code>Blob</code> object; therefore, the
123
* <code>Blob</code> object should have previously brought the
124
* SQL <code>BLOB</code> value's data over to the client from
125
* the database. Otherwise, the new <code>SerialBlob</code> object
126
* will contain no data.
127
*
128
* @param blob the <code>Blob</code> object from which this
129
* <code>SerialBlob</code> object is to be constructed;
130
* cannot be null.
131
* @throws SerialException if an error occurs during serialization
132
* @throws SQLException if the <code>Blob</code> passed to this
133
* to this constructor is a <code>null</code>.
134
* @see java.sql.Blob
135
*/
136
public SerialBlob (Blob blob)
137
throws SerialException, SQLException {
138
139
if (blob == null) {
140
throw new SQLException(
141
"Cannot instantiate a SerialBlob object with a null Blob object");
142
}
143
144
len = blob.length();
145
buf = blob.getBytes(1, (int)len );
146
this.blob = blob;
147
origLen = len;
148
}
149
150
/**
151
* Copies the specified number of bytes, starting at the given
152
* position, from this <code>SerialBlob</code> object to
153
* another array of bytes.
154
* <P>
155
* Note that if the given number of bytes to be copied is larger than
156
* the length of this <code>SerialBlob</code> object's array of
157
* bytes, the given number will be shortened to the array's length.
158
*
159
* @param pos the ordinal position of the first byte in this
160
* <code>SerialBlob</code> object to be copied;
161
* numbering starts at <code>1</code>; must not be less
162
* than <code>1</code> and must be less than or equal
163
* to the length of this <code>SerialBlob</code> object
164
* @param length the number of bytes to be copied
165
* @return an array of bytes that is a copy of a region of this
166
* <code>SerialBlob</code> object, starting at the given
167
* position and containing the given number of consecutive bytes
168
* @throws SerialException if the given starting position is out of bounds;
169
* if {@code free} had previously been called on this object
170
*/
171
public byte[] getBytes(long pos, int length) throws SerialException {
172
isValid();
173
if (length > len) {
174
length = (int)len;
175
}
176
177
if (pos < 1 || len - pos < 0 ) {
178
throw new SerialException("Invalid arguments: position cannot be "
179
+ "less than 1 or greater than the length of the SerialBlob");
180
}
181
182
pos--; // correct pos to array index
183
184
byte[] b = new byte[length];
185
186
for (int i = 0; i < length; i++) {
187
b[i] = this.buf[(int)pos];
188
pos++;
189
}
190
return b;
191
}
192
193
/**
194
* Retrieves the number of bytes in this <code>SerialBlob</code>
195
* object's array of bytes.
196
*
197
* @return a <code>long</code> indicating the length in bytes of this
198
* <code>SerialBlob</code> object's array of bytes
199
* @throws SerialException if an error occurs;
200
* if {@code free} had previously been called on this object
201
*/
202
public long length() throws SerialException {
203
isValid();
204
return len;
205
}
206
207
/**
208
* Returns this <code>SerialBlob</code> object as an input stream.
209
* Unlike the related method, <code>setBinaryStream</code>,
210
* a stream is produced regardless of whether the <code>SerialBlob</code>
211
* was created with a <code>Blob</code> object or a <code>byte</code> array.
212
*
213
* @return a <code>java.io.InputStream</code> object that contains
214
* this <code>SerialBlob</code> object's array of bytes
215
* @throws SerialException if an error occurs;
216
* if {@code free} had previously been called on this object
217
* @see #setBinaryStream
218
*/
219
public java.io.InputStream getBinaryStream() throws SerialException {
220
isValid();
221
InputStream stream = new ByteArrayInputStream(buf);
222
return stream;
223
}
224
225
/**
226
* Returns the position in this <code>SerialBlob</code> object where
227
* the given pattern of bytes begins, starting the search at the
228
* specified position.
229
*
230
* @param pattern the pattern of bytes for which to search
231
* @param start the position of the byte in this
232
* <code>SerialBlob</code> object from which to begin
233
* the search; the first position is <code>1</code>;
234
* must not be less than <code>1</code> nor greater than
235
* the length of this <code>SerialBlob</code> object
236
* @return the position in this <code>SerialBlob</code> object
237
* where the given pattern begins, starting at the specified
238
* position; <code>-1</code> if the pattern is not found
239
* or the given starting position is out of bounds; position
240
* numbering for the return value starts at <code>1</code>
241
* @throws SerialException if an error occurs when serializing the blob;
242
* if {@code free} had previously been called on this object
243
* @throws SQLException if there is an error accessing the <code>BLOB</code>
244
* value from the database
245
*/
246
public long position(byte[] pattern, long start)
247
throws SerialException, SQLException {
248
249
isValid();
250
if (start < 1 || start > len) {
251
return -1;
252
}
253
254
int pos = (int)start-1; // internally Blobs are stored as arrays.
255
int i = 0;
256
long patlen = pattern.length;
257
258
while (pos < len) {
259
if (pattern[i] == buf[pos]) {
260
if (i + 1 == patlen) {
261
return (pos + 1) - (patlen - 1);
262
}
263
i++; pos++; // increment pos, and i
264
} else if (pattern[i] != buf[pos]) {
265
pos++; // increment pos only
266
}
267
}
268
return -1; // not found
269
}
270
271
/**
272
* Returns the position in this <code>SerialBlob</code> object where
273
* the given <code>Blob</code> object begins, starting the search at the
274
* specified position.
275
*
276
* @param pattern the <code>Blob</code> object for which to search;
277
* @param start the position of the byte in this
278
* <code>SerialBlob</code> object from which to begin
279
* the search; the first position is <code>1</code>;
280
* must not be less than <code>1</code> nor greater than
281
* the length of this <code>SerialBlob</code> object
282
* @return the position in this <code>SerialBlob</code> object
283
* where the given <code>Blob</code> object begins, starting
284
* at the specified position; <code>-1</code> if the pattern is
285
* not found or the given starting position is out of bounds;
286
* position numbering for the return value starts at <code>1</code>
287
* @throws SerialException if an error occurs when serializing the blob;
288
* if {@code free} had previously been called on this object
289
* @throws SQLException if there is an error accessing the <code>BLOB</code>
290
* value from the database
291
*/
292
public long position(Blob pattern, long start)
293
throws SerialException, SQLException {
294
isValid();
295
return position(pattern.getBytes(1, (int)(pattern.length())), start);
296
}
297
298
/**
299
* Writes the given array of bytes to the <code>BLOB</code> value that
300
* this <code>Blob</code> object represents, starting at position
301
* <code>pos</code>, and returns the number of bytes written.
302
*
303
* @param pos the position in the SQL <code>BLOB</code> value at which
304
* to start writing. The first position is <code>1</code>;
305
* must not be less than <code>1</code> nor greater than
306
* the length of this <code>SerialBlob</code> object.
307
* @param bytes the array of bytes to be written to the <code>BLOB</code>
308
* value that this <code>Blob</code> object represents
309
* @return the number of bytes written
310
* @throws SerialException if there is an error accessing the
311
* <code>BLOB</code> value; or if an invalid position is set; if an
312
* invalid offset value is set;
313
* if {@code free} had previously been called on this object
314
* @throws SQLException if there is an error accessing the <code>BLOB</code>
315
* value from the database
316
* @see #getBytes
317
*/
318
public int setBytes(long pos, byte[] bytes)
319
throws SerialException, SQLException {
320
return setBytes(pos, bytes, 0, bytes.length);
321
}
322
323
/**
324
* Writes all or part of the given <code>byte</code> array to the
325
* <code>BLOB</code> value that this <code>Blob</code> object represents
326
* and returns the number of bytes written.
327
* Writing starts at position <code>pos</code> in the <code>BLOB</code>
328
* value; <i>len</i> bytes from the given byte array are written.
329
*
330
* @param pos the position in the <code>BLOB</code> object at which
331
* to start writing. The first position is <code>1</code>;
332
* must not be less than <code>1</code> nor greater than
333
* the length of this <code>SerialBlob</code> object.
334
* @param bytes the array of bytes to be written to the <code>BLOB</code>
335
* value
336
* @param offset the offset in the <code>byte</code> array at which
337
* to start reading the bytes. The first offset position is
338
* <code>0</code>; must not be less than <code>0</code> nor greater
339
* than the length of the <code>byte</code> array
340
* @param length the number of bytes to be written to the
341
* <code>BLOB</code> value from the array of bytes <i>bytes</i>.
342
*
343
* @return the number of bytes written
344
* @throws SerialException if there is an error accessing the
345
* <code>BLOB</code> value; if an invalid position is set; if an
346
* invalid offset value is set; if number of bytes to be written
347
* is greater than the <code>SerialBlob</code> length; or the combined
348
* values of the length and offset is greater than the Blob buffer;
349
* if {@code free} had previously been called on this object
350
* @throws SQLException if there is an error accessing the <code>BLOB</code>
351
* value from the database.
352
* @see #getBytes
353
*/
354
public int setBytes(long pos, byte[] bytes, int offset, int length)
355
throws SerialException, SQLException {
356
357
isValid();
358
if (offset < 0 || offset > bytes.length) {
359
throw new SerialException("Invalid offset in byte array set");
360
}
361
362
if (pos < 1 || pos > this.length()) {
363
throw new SerialException("Invalid position in BLOB object set");
364
}
365
366
if ((long)(length) > origLen) {
367
throw new SerialException("Buffer is not sufficient to hold the value");
368
}
369
370
if ((length + offset) > bytes.length) {
371
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
372
"and length that is greater that the Blob buffer");
373
}
374
375
int i = 0;
376
pos--; // correct to array indexing
377
while ( i < length || (offset + i +1) < (bytes.length-offset) ) {
378
this.buf[(int)pos + i] = bytes[offset + i ];
379
i++;
380
}
381
return i;
382
}
383
384
/**
385
* Retrieves a stream that can be used to write to the <code>BLOB</code>
386
* value that this <code>Blob</code> object represents. The stream begins
387
* at position <code>pos</code>. This method forwards the
388
* <code>setBinaryStream()</code> call to the underlying <code>Blob</code> in
389
* the event that this <code>SerialBlob</code> object is instantiated with a
390
* <code>Blob</code>. If this <code>SerialBlob</code> is instantiated with
391
* a <code>byte</code> array, a <code>SerialException</code> is thrown.
392
*
393
* @param pos the position in the <code>BLOB</code> value at which
394
* to start writing
395
* @return a <code>java.io.OutputStream</code> object to which data can
396
* be written
397
* @throws SQLException if there is an error accessing the
398
* <code>BLOB</code> value
399
* @throws SerialException if the SerialBlob in not instantiated with a
400
* <code>Blob</code> object that supports <code>setBinaryStream()</code>;
401
* if {@code free} had previously been called on this object
402
* @see #getBinaryStream
403
*/
404
public java.io.OutputStream setBinaryStream(long pos)
405
throws SerialException, SQLException {
406
407
isValid();
408
if (this.blob != null) {
409
return this.blob.setBinaryStream(pos);
410
} else {
411
throw new SerialException("Unsupported operation. SerialBlob cannot " +
412
"return a writable binary stream, unless instantiated with a Blob object " +
413
"that provides a setBinaryStream() implementation");
414
}
415
}
416
417
/**
418
* Truncates the <code>BLOB</code> value that this <code>Blob</code>
419
* object represents to be <code>len</code> bytes in length.
420
*
421
* @param length the length, in bytes, to which the <code>BLOB</code>
422
* value that this <code>Blob</code> object represents should be
423
* truncated
424
* @throws SerialException if there is an error accessing the Blob value;
425
* or the length to truncate is greater that the SerialBlob length;
426
* if {@code free} had previously been called on this object
427
*/
428
public void truncate(long length) throws SerialException {
429
isValid();
430
if (length > len) {
431
throw new SerialException(
432
"Length more than what can be truncated");
433
} else if((int)length == 0) {
434
buf = new byte[0];
435
len = length;
436
} else {
437
len = length;
438
buf = this.getBytes(1, (int)len);
439
}
440
}
441
442
443
/**
444
* Returns an
445
* <code>InputStream</code> object that contains a partial
446
* {@code Blob} value, starting with the byte specified by pos, which is
447
* length bytes in length.
448
*
449
* @param pos the offset to the first byte of the partial value to be
450
* retrieved. The first byte in the {@code Blob} is at position 1
451
* @param length the length in bytes of the partial value to be retrieved
452
* @return
453
* <code>InputStream</code> through which the partial {@code Blob} value can
454
* be read.
455
* @throws SQLException if pos is less than 1 or if pos is greater than the
456
* number of bytes in the {@code Blob} or if pos + length is greater than
457
* the number of bytes in the {@code Blob}
458
* @throws SerialException if the {@code free} method had been previously
459
* called on this object
460
*
461
* @since 1.6
462
*/
463
public InputStream getBinaryStream(long pos, long length) throws SQLException {
464
isValid();
465
if (pos < 1 || pos > this.length()) {
466
throw new SerialException("Invalid position in BLOB object set");
467
}
468
if (length < 1 || length > len - pos + 1) {
469
throw new SerialException(
470
"length is < 1 or pos + length > total number of bytes");
471
}
472
return new ByteArrayInputStream(buf, (int) pos - 1, (int) length);
473
}
474
475
476
/**
477
* This method frees the {@code SeriableBlob} object and releases the
478
* resources that it holds. The object is invalid once the {@code free}
479
* method is called. <p> If {@code free} is called multiple times, the
480
* subsequent calls to {@code free} are treated as a no-op. </P>
481
*
482
* @throws SQLException if an error occurs releasing the Blob's resources
483
* @since 1.6
484
*/
485
public void free() throws SQLException {
486
if (buf != null) {
487
buf = null;
488
if (blob != null) {
489
blob.free();
490
}
491
blob = null;
492
}
493
}
494
495
/**
496
* Compares this SerialBlob to the specified object. The result is {@code
497
* true} if and only if the argument is not {@code null} and is a {@code
498
* SerialBlob} object that represents the same sequence of bytes as this
499
* object.
500
*
501
* @param obj The object to compare this {@code SerialBlob} against
502
*
503
* @return {@code true} if the given object represents a {@code SerialBlob}
504
* equivalent to this SerialBlob, {@code false} otherwise
505
*
506
*/
507
public boolean equals(Object obj) {
508
if (this == obj) {
509
return true;
510
}
511
if (obj instanceof SerialBlob) {
512
SerialBlob sb = (SerialBlob)obj;
513
if (this.len == sb.len) {
514
return Arrays.equals(buf, sb.buf);
515
}
516
}
517
return false;
518
}
519
520
/**
521
* Returns a hash code for this {@code SerialBlob}.
522
* @return a hash code value for this object.
523
*/
524
public int hashCode() {
525
return ((31 + Arrays.hashCode(buf)) * 31 + (int)len) * 31 + (int)origLen;
526
}
527
528
/**
529
* Returns a clone of this {@code SerialBlob}. The copy will contain a
530
* reference to a clone of the internal byte array, not a reference
531
* to the original internal byte array of this {@code SerialBlob} object.
532
* The underlying {@code Blob} object will be set to null.
533
*
534
* @return a clone of this SerialBlob
535
*/
536
public Object clone() {
537
try {
538
SerialBlob sb = (SerialBlob) super.clone();
539
sb.buf = (buf != null) ? Arrays.copyOf(buf, (int)len) : null;
540
sb.blob = null;
541
return sb;
542
} catch (CloneNotSupportedException ex) {
543
// this shouldn't happen, since we are Cloneable
544
throw new InternalError();
545
}
546
}
547
548
/**
549
* readObject is called to restore the state of the SerialBlob from
550
* a stream.
551
*/
552
private void readObject(ObjectInputStream s)
553
throws IOException, ClassNotFoundException {
554
555
ObjectInputStream.GetField fields = s.readFields();
556
byte[] tmp = (byte[])fields.get("buf", null);
557
if (tmp == null)
558
throw new InvalidObjectException("buf is null and should not be!");
559
buf = tmp.clone();
560
len = fields.get("len", 0L);
561
if (buf.length != len)
562
throw new InvalidObjectException("buf is not the expected size");
563
origLen = fields.get("origLen", 0L);
564
blob = (Blob) fields.get("blob", null);
565
}
566
567
/**
568
* writeObject is called to save the state of the SerialBlob
569
* to a stream.
570
*/
571
private void writeObject(ObjectOutputStream s)
572
throws IOException, ClassNotFoundException {
573
574
ObjectOutputStream.PutField fields = s.putFields();
575
fields.put("buf", buf);
576
fields.put("len", len);
577
fields.put("origLen", origLen);
578
// Note: this check to see if it is an instance of Serializable
579
// is for backwards compatibiity
580
fields.put("blob", blob instanceof Serializable ? blob : null);
581
s.writeFields();
582
}
583
584
/**
585
* Check to see if this object had previously had its {@code free} method
586
* called
587
*
588
* @throws SerialException
589
*/
590
private void isValid() throws SerialException {
591
if (buf == null) {
592
throw new SerialException("Error: You cannot call a method on a " +
593
"SerialBlob instance once free() has been called.");
594
}
595
}
596
597
/**
598
* The identifier that assists in the serialization of this
599
* {@code SerialBlob} object.
600
*/
601
static final long serialVersionUID = -8144641928112860441L;
602
}
603
604