jdk/src/share/classes/javax/sql/rowset/serial/SerialBlob.java
changeset 14781 701d0765f75f
parent 14337 a003c6a54cb6
child 18564 f9db68ff2cbb
equal deleted inserted replaced
14780:a65826af2aa4 14781:701d0765f75f
    49  * <code>SerialBlob</code> object as an array of bytes or as a stream.
    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
    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
    51  * <code>Blob</code> object within a <code>SerialBlob</code> object
    52  * and to update or truncate a <code>Blob</code> object.
    52  * and to update or truncate a <code>Blob</code> object.
    53  *
    53  *
       
    54  * <h4> Thread safety </h4>
       
    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  *
    54  * @author Jonathan Bruce
    60  * @author Jonathan Bruce
    55  */
    61  */
    56 public class SerialBlob implements Blob, Serializable, Cloneable {
    62 public class SerialBlob implements Blob, Serializable, Cloneable {
    57 
    63 
    58     /**
    64     /**
    74      * @serial
    80      * @serial
    75      */
    81      */
    76     private long len;
    82     private long len;
    77 
    83 
    78     /**
    84     /**
    79      * The orginal number of bytes in this <code>SerialBlob</code> object's
    85      * The original number of bytes in this <code>SerialBlob</code> object's
    80      * array of bytes when it was first established.
    86      * array of bytes when it was first established.
    81      * @serial
    87      * @serial
    82      */
    88      */
    83     private long origLen;
    89     private long origLen;
    84 
    90 
   158      *            to the length of this <code>SerialBlob</code> object
   164      *            to the length of this <code>SerialBlob</code> object
   159      * @param length the number of bytes to be copied
   165      * @param length the number of bytes to be copied
   160      * @return an array of bytes that is a copy of a region of this
   166      * @return an array of bytes that is a copy of a region of this
   161      *         <code>SerialBlob</code> object, starting at the given
   167      *         <code>SerialBlob</code> object, starting at the given
   162      *         position and containing the given number of consecutive bytes
   168      *         position and containing the given number of consecutive bytes
   163      * @throws SerialException if the given starting position is out of bounds
   169      * @throws SerialException if the given starting position is out of bounds;
       
   170      * if {@code free} had previously been called on this object
   164      */
   171      */
   165     public byte[] getBytes(long pos, int length) throws SerialException {
   172     public byte[] getBytes(long pos, int length) throws SerialException {
       
   173         isValid();
   166         if (length > len) {
   174         if (length > len) {
   167             length = (int)len;
   175             length = (int)len;
   168         }
   176         }
   169 
   177 
   170         if (pos < 1 || len - pos < 0 ) {
   178         if (pos < 1 || len - pos < 0 ) {
   187      * Retrieves the number of bytes in this <code>SerialBlob</code>
   195      * Retrieves the number of bytes in this <code>SerialBlob</code>
   188      * object's array of bytes.
   196      * object's array of bytes.
   189      *
   197      *
   190      * @return a <code>long</code> indicating the length in bytes of this
   198      * @return a <code>long</code> indicating the length in bytes of this
   191      *         <code>SerialBlob</code> object's array of bytes
   199      *         <code>SerialBlob</code> object's array of bytes
   192      * @throws SerialException if an error occurs
   200      * @throws SerialException if an error occurs;
       
   201      * if {@code free} had previously been called on this object
   193      */
   202      */
   194     public long length() throws SerialException {
   203     public long length() throws SerialException {
       
   204         isValid();
   195         return len;
   205         return len;
   196     }
   206     }
   197 
   207 
   198     /**
   208     /**
   199      * Returns this <code>SerialBlob</code> object as an input stream.
   209      * Returns this <code>SerialBlob</code> object as an input stream.
   201      * a stream is produced regardless of whether the <code>SerialBlob</code>
   211      * a stream is produced regardless of whether the <code>SerialBlob</code>
   202      * was created with a <code>Blob</code> object or a <code>byte</code> array.
   212      * was created with a <code>Blob</code> object or a <code>byte</code> array.
   203      *
   213      *
   204      * @return a <code>java.io.InputStream</code> object that contains
   214      * @return a <code>java.io.InputStream</code> object that contains
   205      *         this <code>SerialBlob</code> object's array of bytes
   215      *         this <code>SerialBlob</code> object's array of bytes
   206      * @throws SerialException if an error occurs
   216      * @throws SerialException if an error occurs;
       
   217      * if {@code free} had previously been called on this object
   207      * @see #setBinaryStream
   218      * @see #setBinaryStream
   208      */
   219      */
   209     public java.io.InputStream getBinaryStream() throws SerialException {
   220     public java.io.InputStream getBinaryStream() throws SerialException {
   210          InputStream stream = new ByteArrayInputStream(buf);
   221         isValid();
   211          return stream;
   222         InputStream stream = new ByteArrayInputStream(buf);
       
   223         return stream;
   212     }
   224     }
   213 
   225 
   214     /**
   226     /**
   215      * Returns the position in this <code>SerialBlob</code> object where
   227      * Returns the position in this <code>SerialBlob</code> object where
   216      * the given pattern of bytes begins, starting the search at the
   228      * the given pattern of bytes begins, starting the search at the
   225      * @return the position in this <code>SerialBlob</code> object
   237      * @return the position in this <code>SerialBlob</code> object
   226      *         where the given pattern begins, starting at the specified
   238      *         where the given pattern begins, starting at the specified
   227      *         position; <code>-1</code> if the pattern is not found
   239      *         position; <code>-1</code> if the pattern is not found
   228      *         or the given starting position is out of bounds; position
   240      *         or the given starting position is out of bounds; position
   229      *         numbering for the return value starts at <code>1</code>
   241      *         numbering for the return value starts at <code>1</code>
   230      * @throws SerialException if an error occurs when serializing the blob
   242      * @throws SerialException if an error occurs when serializing the blob;
       
   243      * if {@code free} had previously been called on this object
   231      * @throws SQLException if there is an error accessing the <code>BLOB</code>
   244      * @throws SQLException if there is an error accessing the <code>BLOB</code>
   232      *         value from the database
   245      *         value from the database
   233      */
   246      */
   234     public long position(byte[] pattern, long start)
   247     public long position(byte[] pattern, long start)
   235                 throws SerialException, SQLException {
   248                 throws SerialException, SQLException {
       
   249         isValid();
   236         if (start < 1 || start > len) {
   250         if (start < 1 || start > len) {
   237             return -1;
   251             return -1;
   238         }
   252         }
   239 
   253 
   240         int pos = (int)start-1; // internally Blobs are stored as arrays.
   254         int pos = (int)start-1; // internally Blobs are stored as arrays.
   268      * @return the position in this <code>SerialBlob</code> object
   282      * @return the position in this <code>SerialBlob</code> object
   269      *         where the given <code>Blob</code> object begins, starting
   283      *         where the given <code>Blob</code> object begins, starting
   270      *         at the specified position; <code>-1</code> if the pattern is
   284      *         at the specified position; <code>-1</code> if the pattern is
   271      *         not found or the given starting position is out of bounds;
   285      *         not found or the given starting position is out of bounds;
   272      *         position numbering for the return value starts at <code>1</code>
   286      *         position numbering for the return value starts at <code>1</code>
   273      * @throws SerialException if an error occurs when serializing the blob
   287      * @throws SerialException if an error occurs when serializing the blob;
       
   288      * if {@code free} had previously been called on this object
   274      * @throws SQLException if there is an error accessing the <code>BLOB</code>
   289      * @throws SQLException if there is an error accessing the <code>BLOB</code>
   275      *         value from the database
   290      *         value from the database
   276      */
   291      */
   277     public long position(Blob pattern, long start)
   292     public long position(Blob pattern, long start)
   278        throws SerialException, SQLException {
   293        throws SerialException, SQLException {
       
   294         isValid();
   279         return position(pattern.getBytes(1, (int)(pattern.length())), start);
   295         return position(pattern.getBytes(1, (int)(pattern.length())), start);
   280     }
   296     }
   281 
   297 
   282     /**
   298     /**
   283      * Writes the given array of bytes to the <code>BLOB</code> value that
   299      * Writes the given array of bytes to the <code>BLOB</code> value that
   291      * @param bytes the array of bytes to be written to the <code>BLOB</code>
   307      * @param bytes the array of bytes to be written to the <code>BLOB</code>
   292      *        value that this <code>Blob</code> object represents
   308      *        value that this <code>Blob</code> object represents
   293      * @return the number of bytes written
   309      * @return the number of bytes written
   294      * @throws SerialException if there is an error accessing the
   310      * @throws SerialException if there is an error accessing the
   295      *     <code>BLOB</code> value; or if an invalid position is set; if an
   311      *     <code>BLOB</code> value; or if an invalid position is set; if an
   296      *     invalid offset value is set
   312      *     invalid offset value is set;
       
   313      * if {@code free} had previously been called on this object
   297      * @throws SQLException if there is an error accessing the <code>BLOB</code>
   314      * @throws SQLException if there is an error accessing the <code>BLOB</code>
   298      *         value from the database
   315      *         value from the database
   299      * @see #getBytes
   316      * @see #getBytes
   300      */
   317      */
   301     public int setBytes(long pos, byte[] bytes)
   318     public int setBytes(long pos, byte[] bytes)
   326      * @return the number of bytes written
   343      * @return the number of bytes written
   327      * @throws SerialException if there is an error accessing the
   344      * @throws SerialException if there is an error accessing the
   328      *     <code>BLOB</code> value; if an invalid position is set; if an
   345      *     <code>BLOB</code> value; if an invalid position is set; if an
   329      *     invalid offset value is set; if number of bytes to be written
   346      *     invalid offset value is set; if number of bytes to be written
   330      *     is greater than the <code>SerialBlob</code> length; or the combined
   347      *     is greater than the <code>SerialBlob</code> length; or the combined
   331      *     values of the length and offset is greater than the Blob buffer
   348      *     values of the length and offset is greater than the Blob buffer;
       
   349      * if {@code free} had previously been called on this object
   332      * @throws SQLException if there is an error accessing the <code>BLOB</code>
   350      * @throws SQLException if there is an error accessing the <code>BLOB</code>
   333      *         value from the database.
   351      *         value from the database.
   334      * @see #getBytes
   352      * @see #getBytes
   335      */
   353      */
   336     public int setBytes(long pos, byte[] bytes, int offset, int length)
   354     public int setBytes(long pos, byte[] bytes, int offset, int length)
   337         throws SerialException, SQLException {
   355         throws SerialException, SQLException {
   338 
   356 
       
   357         isValid();
   339         if (offset < 0 || offset > bytes.length) {
   358         if (offset < 0 || offset > bytes.length) {
   340             throw new SerialException("Invalid offset in byte array set");
   359             throw new SerialException("Invalid offset in byte array set");
   341         }
   360         }
   342 
   361 
   343         if (pos < 1 || pos > this.length()) {
   362         if (pos < 1 || pos > this.length()) {
   376      * @return a <code>java.io.OutputStream</code> object to which data can
   395      * @return a <code>java.io.OutputStream</code> object to which data can
   377      *         be written
   396      *         be written
   378      * @throws SQLException if there is an error accessing the
   397      * @throws SQLException if there is an error accessing the
   379      *            <code>BLOB</code> value
   398      *            <code>BLOB</code> value
   380      * @throws SerialException if the SerialBlob in not instantiated with a
   399      * @throws SerialException if the SerialBlob in not instantiated with a
   381      *     <code>Blob</code> object that supports <code>setBinaryStream()</code>
   400      *     <code>Blob</code> object that supports <code>setBinaryStream()</code>;
       
   401      * if {@code free} had previously been called on this object
   382      * @see #getBinaryStream
   402      * @see #getBinaryStream
   383      */
   403      */
   384     public java.io.OutputStream setBinaryStream(long pos)
   404     public java.io.OutputStream setBinaryStream(long pos)
   385         throws SerialException, SQLException {
   405         throws SerialException, SQLException {
       
   406         isValid();
   386         if (this.blob != null) {
   407         if (this.blob != null) {
   387             return this.blob.setBinaryStream(pos);
   408             return this.blob.setBinaryStream(pos);
   388         } else {
   409         } else {
   389             throw new SerialException("Unsupported operation. SerialBlob cannot " +
   410             throw new SerialException("Unsupported operation. SerialBlob cannot " +
   390                 "return a writable binary stream, unless instantiated with a Blob object " +
   411                 "return a writable binary stream, unless instantiated with a Blob object " +
   398      *
   419      *
   399      * @param length the length, in bytes, to which the <code>BLOB</code>
   420      * @param length the length, in bytes, to which the <code>BLOB</code>
   400      *        value that this <code>Blob</code> object represents should be
   421      *        value that this <code>Blob</code> object represents should be
   401      *        truncated
   422      *        truncated
   402      * @throws SerialException if there is an error accessing the Blob value;
   423      * @throws SerialException if there is an error accessing the Blob value;
   403      *     or the length to truncate is greater that the SerialBlob length
   424      *     or the length to truncate is greater that the SerialBlob length;
       
   425      * if {@code free} had previously been called on this object
   404      */
   426      */
   405     public void truncate(long length) throws SerialException {
   427     public void truncate(long length) throws SerialException {
   406 
   428 
   407          if (length > len) {
   429         isValid();
   408             throw new SerialException
   430         if (length > len) {
   409                ("Length more than what can be truncated");
   431            throw new SerialException
   410          } else if((int)length == 0) {
   432               ("Length more than what can be truncated");
   411               buf = new byte[0];
   433         } else if((int)length == 0) {
   412               len = length;
   434              buf = new byte[0];
   413          } else {
   435              len = length;
   414               len = length;
   436         } else {
   415               buf = this.getBytes(1, (int)len);
   437              len = length;
   416          }
   438              buf = this.getBytes(1, (int)len);
   417     }
   439         }
   418 
   440     }
   419 
   441 
   420     /**
   442 
   421      * Returns an <code>InputStream</code> object that contains a partial <code>Blob</code> value,
   443     /**
   422      * starting  with the byte specified by pos, which is length bytes in length.
   444      * Returns an
   423      *
   445      * <code>InputStream</code> object that contains a partial
   424      * @param pos the offset to the first byte of the partial value to be retrieved.
   446      * {@code Blob} value, starting with the byte specified by pos, which is
   425      *  The first byte in the <code>Blob</code> is at position 1
   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
   426      * @param length the length in bytes of the partial value to be retrieved
   451      * @param length the length in bytes of the partial value to be retrieved
   427      * @return <code>InputStream</code> through which the partial <code>Blob</code> value can be read.
   452      * @return
   428      * @throws SQLException if pos is less than 1 or if pos is greater than the number of bytes
   453      * <code>InputStream</code> through which the partial {@code Blob} value can
   429      * in the <code>Blob</code> or if pos + length is greater than the number of bytes
   454      * be read.
   430      * in the <code>Blob</code>
   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
   431      *
   460      *
   432      * @since 1.6
   461      * @since 1.6
   433      */
   462      */
   434     public InputStream getBinaryStream(long pos,long length) throws SQLException {
   463     public InputStream getBinaryStream(long pos, long length) throws SQLException {
   435         throw new java.lang.UnsupportedOperationException("Not supported");
   464         isValid();
   436     }
   465         if (pos < 1 || pos > this.length()) {
   437 
   466             throw new SerialException("Invalid position in BLOB object set");
   438 
   467         }
   439     /**
   468         if (length < 1 || length > len - pos + 1) {
   440      * This method frees the <code>Blob</code> object and releases the resources that it holds.
   469             throw new SerialException("length is < 1 or pos + length >"
   441      * <code>Blob</code> object. The object is invalid once the <code>free</code>
   470                     + "total number of bytes");
   442      * method is called. If <code>free</code> is called multiple times, the subsequent
   471         }
   443      * calls to <code>free</code> are treated as a no-op.
   472         return new ByteArrayInputStream(buf, (int) pos - 1, (int) length);
   444      *
   473     }
   445      * @throws SQLException if an error occurs releasing
   474 
   446      * the Blob's resources
   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
   447      * @since 1.6
   483      * @since 1.6
   448      */
   484      */
   449     public void free() throws SQLException {
   485     public void free() throws SQLException {
   450         throw new java.lang.UnsupportedOperationException("Not supported");
   486         if (buf != null) {
       
   487             buf = null;
       
   488             if (blob != null) {
       
   489                 blob.free();
       
   490             }
       
   491             blob = null;
       
   492         }
   451     }
   493     }
   452 
   494 
   453     /**
   495     /**
   454      * Compares this SerialBlob to the specified object.  The result is {@code
   496      * Compares this SerialBlob to the specified object.  The result is {@code
   455      * true} if and only if the argument is not {@code null} and is a {@code
   497      * true} if and only if the argument is not {@code null} and is a {@code
   492      * @return  a clone of this SerialBlob
   534      * @return  a clone of this SerialBlob
   493      */
   535      */
   494     public Object clone() {
   536     public Object clone() {
   495         try {
   537         try {
   496             SerialBlob sb = (SerialBlob) super.clone();
   538             SerialBlob sb = (SerialBlob) super.clone();
   497             sb.buf = Arrays.copyOf(buf, (int)len);
   539             sb.buf =  (buf != null) ? Arrays.copyOf(buf, (int)len) : null;
   498             sb.blob = null;
   540             sb.blob = null;
   499             return sb;
   541             return sb;
   500         } catch (CloneNotSupportedException ex) {
   542         } catch (CloneNotSupportedException ex) {
   501             // this shouldn't happen, since we are Cloneable
   543             // this shouldn't happen, since we are Cloneable
   502             throw new InternalError();
   544             throw new InternalError();
   539         fields.put("blob", blob instanceof Serializable ? blob : null);
   581         fields.put("blob", blob instanceof Serializable ? blob : null);
   540         s.writeFields();
   582         s.writeFields();
   541     }
   583     }
   542 
   584 
   543     /**
   585     /**
   544          * The identifier that assists in the serialization of this <code>SerialBlob</code>
   586      * Check to see if this object had previously had its {@code free} method
   545      * object.
   587      * called
   546      */
   588      *
   547 
   589      * @throws SerialException
       
   590      */
       
   591     private void isValid() throws SerialException {
       
   592         if (buf == null) {
       
   593             throw new SerialException("Error: You cannot call a method on a "
       
   594                     + "SerialBlob instance once free() has been called.");
       
   595         }
       
   596     }
       
   597 
       
   598     /**
       
   599      * The identifier that assists in the serialization of this
       
   600      * {@code SerialBlob} object.
       
   601      */
   548     static final long serialVersionUID = -8144641928112860441L;
   602     static final long serialVersionUID = -8144641928112860441L;
   549 }
   603 }