# HG changeset patch # User lancea # Date 1355363865 18000 # Node ID 701d0765f75f8cd3b20e8071c8e757486ba1ab8e # Parent a65826af2aa488a81d23fd6f966fd626ca44adbb 8004357: Implement various methods in SerialBlob/Clob/Array and specify Thread Safety Reviewed-by: naoto diff -r a65826af2aa4 -r 701d0765f75f jdk/src/share/classes/javax/sql/rowset/serial/SerialArray.java --- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialArray.java Thu Dec 13 08:11:38 2012 +0800 +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialArray.java Wed Dec 12 20:57:45 2012 -0500 @@ -31,6 +31,7 @@ import java.net.URL; import java.util.Arrays; + /** * A serialized version of an Array * object, which is the mapping in the Java programming language of an SQL @@ -41,44 +42,52 @@ * methods for getting the base type and the SQL name for the base type, and * methods for copying all or part of a SerialArray object. *

+ * * Note: In order for this class to function correctly, a connection to the * data source * must be available in order for the SQL Array object to be * materialized (have all of its elements brought to the client server) * if necessary. At this time, logical pointers to the data in the data source, * such as locators, are not currently supported. + * + *

Thread safety

+ * + * A SerialArray is not safe for use by multiple concurrent threads. If a + * SerialArray is to be used by more than one thread then access to the + * SerialArray should be controlled by appropriate synchronization. + * */ public class SerialArray implements Array, Serializable, Cloneable { - /** - * A serialized array in which each element is an Object - * in the Java programming language that represents an element - * in the SQL ARRAY value. - * @serial - */ + /** + * A serialized array in which each element is an Object + * in the Java programming language that represents an element + * in the SQL ARRAY value. + * @serial + */ private Object[] elements; - /** - * The SQL type of the elements in this SerialArray object. The - * type is expressed as one of the constants from the class - * java.sql.Types. - * @serial - */ + /** + * The SQL type of the elements in this SerialArray object. The + * type is expressed as one of the constants from the class + * java.sql.Types. + * @serial + */ private int baseType; - /** - * The type name used by the DBMS for the elements in the SQL ARRAY - * value that this SerialArray object represents. - * @serial - */ + /** + * The type name used by the DBMS for the elements in the SQL ARRAY + * value that this SerialArray object represents. + * @serial + */ private String baseTypeName; - /** - * The number of elements in this SerialArray object, which - * is also the number of elements in the SQL ARRAY value - * that this SerialArray object represents. - * @serial - */ + /** + * The number of elements in this SerialArray object, which + * is also the number of elements in the SQL ARRAY value + * that this SerialArray object represents. + * @serial + */ private int len; /** @@ -192,24 +201,19 @@ } /** - * This method frees the Array object and releases the resources that - * it holds. The object is invalid once the free - * method is called. - *

- * After free has been called, any attempt to invoke a - * method other than free will result in a SQLException - * being thrown. If free is called multiple times, the subsequent - * calls to free are treated as a no-op. - *

+ * This method frees the {@code SeriableArray} object and releases the + * resources that it holds. The object is invalid once the {@code free} + * method is called.

If {@code free} is called multiple times, the + * subsequent calls to {@code free} are treated as a no-op.

* - * @throws SQLException if an error occurs releasing - * the Array's resources - * @exception SQLFeatureNotSupportedException if the JDBC driver does not support - * this method + * @throws SQLException if an error occurs releasing the SerialArray's resources * @since 1.6 */ public void free() throws SQLException { - throw new SQLFeatureNotSupportedException("Feature not supported"); + if (elements != null) { + elements = null; + baseTypeName= null; + } } /** @@ -292,129 +296,140 @@ } - /** - * Returns a new array that is a copy of this SerialArray - * object. - * - * @return a copy of this SerialArray object as an - * Object in the Java programming language - * @throws SerialException if an error occurs retrieving a copy of - * this SerialArray object - */ + /** + * Returns a new array that is a copy of this SerialArray + * object. + * + * @return a copy of this SerialArray object as an + * Object in the Java programming language + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object + */ public Object getArray() throws SerialException { + isValid(); Object dst = new Object[len]; System.arraycopy((Object)elements, 0, dst, 0, len); return dst; } //[if an error occurstype map used??] - /** - * Returns a new array that is a copy of this SerialArray - * object, using the given type map for the custom - * mapping of each element when the elements are SQL UDTs. - *

- * This method does custom mapping if the array elements are a UDT - * and the given type map has an entry for that UDT. + /** + * Returns a new array that is a copy of this SerialArray + * object, using the given type map for the custom + * mapping of each element when the elements are SQL UDTs. + *

+ * This method does custom mapping if the array elements are a UDT + * and the given type map has an entry for that UDT. * Custom mapping is recursive, - * meaning that if, for instance, an element of an SQL structured type - * is an SQL structured type that itself has an element that is an SQL - * structured type, each structured type that has a custom mapping will be - * mapped according to the given type map. - * + * meaning that if, for instance, an element of an SQL structured type + * is an SQL structured type that itself has an element that is an SQL + * structured type, each structured type that has a custom mapping will be + * mapped according to the given type map. + * * @param map a java.util.Map object in which * each entry consists of 1) a String object * giving the fully qualified name of a UDT and 2) the * Class object for the SQLData implementation * that defines how the UDT is to be mapped - * @return a copy of this SerialArray object as an - * Object in the Java programming language - * @throws SerialException if an error occurs - */ + * @return a copy of this SerialArray object as an + * Object in the Java programming language + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object + */ public Object getArray(Map> map) throws SerialException { + isValid(); Object dst[] = new Object[len]; System.arraycopy((Object)elements, 0, dst, 0, len); return dst; } - /** - * Returns a new array that is a copy of a slice - * of this SerialArray object, starting with the - * element at the given index and containing the given number - * of consecutive elements. - * - * @param index the index into this SerialArray object - * of the first element to be copied; - * the index of the first element is 0 - * @param count the number of consecutive elements to be copied, starting - * at the given index - * @return a copy of the designated elements in this SerialArray - * object as an Object in the Java programming language - * @throws SerialException if an error occurs - */ + /** + * Returns a new array that is a copy of a slice + * of this SerialArray object, starting with the + * element at the given index and containing the given number + * of consecutive elements. + * + * @param index the index into this SerialArray object + * of the first element to be copied; + * the index of the first element is 0 + * @param count the number of consecutive elements to be copied, starting + * at the given index + * @return a copy of the designated elements in this SerialArray + * object as an Object in the Java programming language + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object + */ public Object getArray(long index, int count) throws SerialException { + isValid(); Object dst = new Object[count]; System.arraycopy((Object)elements, (int)index, dst, 0, count); return dst; } - /** - * Returns a new array that is a copy of a slice - * of this SerialArray object, starting with the - * element at the given index and containing the given number - * of consecutive elements. - *

- * This method does custom mapping if the array elements are a UDT - * and the given type map has an entry for that UDT. + /** + * Returns a new array that is a copy of a slice + * of this SerialArray object, starting with the + * element at the given index and containing the given number + * of consecutive elements. + *

+ * This method does custom mapping if the array elements are a UDT + * and the given type map has an entry for that UDT. * Custom mapping is recursive, - * meaning that if, for instance, an element of an SQL structured type - * is an SQL structured type that itself has an element that is an SQL - * structured type, each structured type that has a custom mapping will be - * mapped according to the given type map. - * - * @param index the index into this SerialArray object - * of the first element to be copied; the index of the - * first element in the array is 0 - * @param count the number of consecutive elements to be copied, starting - * at the given index + * meaning that if, for instance, an element of an SQL structured type + * is an SQL structured type that itself has an element that is an SQL + * structured type, each structured type that has a custom mapping will be + * mapped according to the given type map. + * + * @param index the index into this SerialArray object + * of the first element to be copied; the index of the + * first element in the array is 0 + * @param count the number of consecutive elements to be copied, starting + * at the given index * @param map a java.util.Map object in which * each entry consists of 1) a String object * giving the fully qualified name of a UDT and 2) the * Class object for the SQLData implementation * that defines how the UDT is to be mapped - * @return a copy of the designated elements in this SerialArray - * object as an Object in the Java programming language - * @throws SerialException if an error occurs - */ + * @return a copy of the designated elements in this SerialArray + * object as an Object in the Java programming language + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object + */ public Object getArray(long index, int count, Map> map) throws SerialException { + isValid(); Object dst = new Object[count]; System.arraycopy((Object)elements, (int)index, dst, 0, count); return dst; } - /** - * Retrieves the SQL type of the elements in this SerialArray - * object. The int returned is one of the constants in the class - * java.sql.Types. - * - * @return one of the constants in java.sql.Types, indicating - * the SQL type of the elements in this SerialArray object - * @throws SerialException if an error occurs - */ + /** + * Retrieves the SQL type of the elements in this SerialArray + * object. The int returned is one of the constants in the class + * java.sql.Types. + * + * @return one of the constants in java.sql.Types, indicating + * the SQL type of the elements in this SerialArray object + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object + */ public int getBaseType() throws SerialException { + isValid(); return baseType; } - /** - * Retrieves the DBMS-specific type name for the elements in this - * SerialArray object. - * - * @return the SQL type name used by the DBMS for the base type of this + /** + * Retrieves the DBMS-specific type name for the elements in this + * SerialArray object. + * + * @return the SQL type name used by the DBMS for the base type of this * SerialArray object - * @throws SerialException if an error occurs - */ + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object + */ public String getBaseTypeName() throws SerialException { + isValid(); return baseTypeName; } @@ -434,11 +449,13 @@ * @return a ResultSet object containing the designated * elements in this SerialArray object, with a * separate row for each element - * @throws SerialException, which in turn throws an - * UnsupportedOperationException, if this method is called + * @throws SerialException if called with the cause set to + * {@code UnsupportedOperationException} */ public ResultSet getResultSet(long index, int count) throws SerialException { - throw new UnsupportedOperationException(); + SerialException se = new SerialException(); + se.initCause(new UnsupportedOperationException()); + throw se; } /** @@ -461,13 +478,15 @@ * @return a ResultSet object containing all of the * elements in this SerialArray object, with a * separate row for each element - * @throws SerialException, which in turn throws an - * UnsupportedOperationException, if this method is called + * @throws SerialException if called with the cause set to + * {@code UnsupportedOperationException} */ public ResultSet getResultSet(Map> map) throws SerialException { - throw new UnsupportedOperationException(); + SerialException se = new SerialException(); + se.initCause(new UnsupportedOperationException()); + throw se; } /** @@ -480,11 +499,13 @@ * @return a ResultSet object containing all of the * elements in this SerialArray object, with a * separate row for each element - * @throws SerialException if called, which in turn throws an - * UnsupportedOperationException, if this method is called + * @throws SerialException if called with the cause set to + * {@code UnsupportedOperationException} */ public ResultSet getResultSet() throws SerialException { - throw new UnsupportedOperationException(); + SerialException se = new SerialException(); + se.initCause(new UnsupportedOperationException()); + throw se; } @@ -514,16 +535,19 @@ * @return a ResultSet object containing the designated * elements in this SerialArray object, with a * separate row for each element - * @throws SerialException if called, which in turn throws an - * UnsupportedOperationException + * @throws SerialException if called with the cause set to + * {@code UnsupportedOperationException} */ public ResultSet getResultSet(long index, int count, Map> map) throws SerialException { - throw new UnsupportedOperationException(); + SerialException se = new SerialException(); + se.initCause(new UnsupportedOperationException()); + throw se; } + /** * Compares this SerialArray to the specified object. The result is {@code * true} if and only if the argument is not {@code null} and is a {@code @@ -566,12 +590,12 @@ * reference to a clone of the underlying objects array, not a reference * to the original underlying object array of this {@code SerialArray} object. * - * @return a clone of this SerialArray + * @return a clone of this SerialArray */ public Object clone() { try { SerialArray sa = (SerialArray) super.clone(); - sa.elements = Arrays.copyOf(elements, len); + sa.elements = (elements != null) ? Arrays.copyOf(elements, len) : null; return sa; } catch (CloneNotSupportedException ex) { // this shouldn't happen, since we are Cloneable @@ -616,6 +640,19 @@ } /** + * Check to see if this object had previously had its {@code free} method + * called + * + * @throws SerialException + */ + private void isValid() throws SerialException { + if (elements == null) { + throw new SerialException("Error: You cannot call a method on a " + + "SerialArray instance once free() has been called."); + } + } + + /** * The identifier that assists in the serialization of this SerialArray * object. */ diff -r a65826af2aa4 -r 701d0765f75f jdk/src/share/classes/javax/sql/rowset/serial/SerialBlob.java --- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialBlob.java Thu Dec 13 08:11:38 2012 +0800 +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialBlob.java Wed Dec 12 20:57:45 2012 -0500 @@ -51,6 +51,12 @@ * Blob object within a SerialBlob object * and to update or truncate a Blob object. * + *

Thread safety

+ * + *

A SerialBlob is not safe for use by multiple concurrent threads. If a + * SerialBlob is to be used by more than one thread then access to the SerialBlob + * should be controlled by appropriate synchronization. + * * @author Jonathan Bruce */ public class SerialBlob implements Blob, Serializable, Cloneable { @@ -76,7 +82,7 @@ private long len; /** - * The orginal number of bytes in this SerialBlob object's + * The original number of bytes in this SerialBlob object's * array of bytes when it was first established. * @serial */ @@ -160,9 +166,11 @@ * @return an array of bytes that is a copy of a region of this * SerialBlob object, starting at the given * position and containing the given number of consecutive bytes - * @throws SerialException if the given starting position is out of bounds + * @throws SerialException if the given starting position is out of bounds; + * if {@code free} had previously been called on this object */ public byte[] getBytes(long pos, int length) throws SerialException { + isValid(); if (length > len) { length = (int)len; } @@ -189,9 +197,11 @@ * * @return a long indicating the length in bytes of this * SerialBlob object's array of bytes - * @throws SerialException if an error occurs + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object */ public long length() throws SerialException { + isValid(); return len; } @@ -203,12 +213,14 @@ * * @return a java.io.InputStream object that contains * this SerialBlob object's array of bytes - * @throws SerialException if an error occurs + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object * @see #setBinaryStream */ public java.io.InputStream getBinaryStream() throws SerialException { - InputStream stream = new ByteArrayInputStream(buf); - return stream; + isValid(); + InputStream stream = new ByteArrayInputStream(buf); + return stream; } /** @@ -227,12 +239,14 @@ * position; -1 if the pattern is not found * or the given starting position is out of bounds; position * numbering for the return value starts at 1 - * @throws SerialException if an error occurs when serializing the blob + * @throws SerialException if an error occurs when serializing the blob; + * if {@code free} had previously been called on this object * @throws SQLException if there is an error accessing the BLOB * value from the database */ public long position(byte[] pattern, long start) throws SerialException, SQLException { + isValid(); if (start < 1 || start > len) { return -1; } @@ -270,12 +284,14 @@ * at the specified position; -1 if the pattern is * not found or the given starting position is out of bounds; * position numbering for the return value starts at 1 - * @throws SerialException if an error occurs when serializing the blob + * @throws SerialException if an error occurs when serializing the blob; + * if {@code free} had previously been called on this object * @throws SQLException if there is an error accessing the BLOB * value from the database */ public long position(Blob pattern, long start) throws SerialException, SQLException { + isValid(); return position(pattern.getBytes(1, (int)(pattern.length())), start); } @@ -293,7 +309,8 @@ * @return the number of bytes written * @throws SerialException if there is an error accessing the * BLOB value; or if an invalid position is set; if an - * invalid offset value is set + * invalid offset value is set; + * if {@code free} had previously been called on this object * @throws SQLException if there is an error accessing the BLOB * value from the database * @see #getBytes @@ -328,7 +345,8 @@ * BLOB value; if an invalid position is set; if an * invalid offset value is set; if number of bytes to be written * is greater than the SerialBlob length; or the combined - * values of the length and offset is greater than the Blob buffer + * values of the length and offset is greater than the Blob buffer; + * if {@code free} had previously been called on this object * @throws SQLException if there is an error accessing the BLOB * value from the database. * @see #getBytes @@ -336,6 +354,7 @@ public int setBytes(long pos, byte[] bytes, int offset, int length) throws SerialException, SQLException { + isValid(); if (offset < 0 || offset > bytes.length) { throw new SerialException("Invalid offset in byte array set"); } @@ -378,11 +397,13 @@ * @throws SQLException if there is an error accessing the * BLOB value * @throws SerialException if the SerialBlob in not instantiated with a - * Blob object that supports setBinaryStream() + * Blob object that supports setBinaryStream(); + * if {@code free} had previously been called on this object * @see #getBinaryStream */ public java.io.OutputStream setBinaryStream(long pos) throws SerialException, SQLException { + isValid(); if (this.blob != null) { return this.blob.setBinaryStream(pos); } else { @@ -400,54 +421,75 @@ * value that this Blob object represents should be * truncated * @throws SerialException if there is an error accessing the Blob value; - * or the length to truncate is greater that the SerialBlob length + * or the length to truncate is greater that the SerialBlob length; + * if {@code free} had previously been called on this object */ public void truncate(long length) throws SerialException { - if (length > len) { - throw new SerialException - ("Length more than what can be truncated"); - } else if((int)length == 0) { - buf = new byte[0]; - len = length; - } else { - len = length; - buf = this.getBytes(1, (int)len); - } + isValid(); + if (length > len) { + throw new SerialException + ("Length more than what can be truncated"); + } else if((int)length == 0) { + buf = new byte[0]; + len = length; + } else { + len = length; + buf = this.getBytes(1, (int)len); + } } /** - * Returns an InputStream object that contains a partial Blob value, - * starting with the byte specified by pos, which is length bytes in length. + * Returns an + * InputStream object that contains a partial + * {@code Blob} value, starting with the byte specified by pos, which is + * length bytes in length. * - * @param pos the offset to the first byte of the partial value to be retrieved. - * The first byte in the Blob is at position 1 + * @param pos the offset to the first byte of the partial value to be + * retrieved. The first byte in the {@code Blob} is at position 1 * @param length the length in bytes of the partial value to be retrieved - * @return InputStream through which the partial Blob value can be read. - * @throws SQLException if pos is less than 1 or if pos is greater than the number of bytes - * in the Blob or if pos + length is greater than the number of bytes - * in the Blob + * @return + * InputStream through which the partial {@code Blob} value can + * be read. + * @throws SQLException if pos is less than 1 or if pos is greater than the + * number of bytes in the {@code Blob} or if pos + length is greater than + * the number of bytes in the {@code Blob} + * @throws SerialException if the {@code free} method had been previously + * called on this object * * @since 1.6 */ - public InputStream getBinaryStream(long pos,long length) throws SQLException { - throw new java.lang.UnsupportedOperationException("Not supported"); + public InputStream getBinaryStream(long pos, long length) throws SQLException { + isValid(); + if (pos < 1 || pos > this.length()) { + throw new SerialException("Invalid position in BLOB object set"); + } + if (length < 1 || length > len - pos + 1) { + throw new SerialException("length is < 1 or pos + length >" + + "total number of bytes"); + } + return new ByteArrayInputStream(buf, (int) pos - 1, (int) length); } /** - * This method frees the Blob object and releases the resources that it holds. - * Blob object. The object is invalid once the free - * method is called. If free is called multiple times, the subsequent - * calls to free are treated as a no-op. + * This method frees the {@code SeriableBlob} object and releases the + * resources that it holds. The object is invalid once the {@code free} + * method is called.

If {@code free} is called multiple times, the + * subsequent calls to {@code free} are treated as a no-op.

* - * @throws SQLException if an error occurs releasing - * the Blob's resources + * @throws SQLException if an error occurs releasing the Blob's resources * @since 1.6 */ public void free() throws SQLException { - throw new java.lang.UnsupportedOperationException("Not supported"); + if (buf != null) { + buf = null; + if (blob != null) { + blob.free(); + } + blob = null; + } } /** @@ -494,7 +536,7 @@ public Object clone() { try { SerialBlob sb = (SerialBlob) super.clone(); - sb.buf = Arrays.copyOf(buf, (int)len); + sb.buf = (buf != null) ? Arrays.copyOf(buf, (int)len) : null; sb.blob = null; return sb; } catch (CloneNotSupportedException ex) { @@ -541,9 +583,21 @@ } /** - * The identifier that assists in the serialization of this SerialBlob - * object. + * Check to see if this object had previously had its {@code free} method + * called + * + * @throws SerialException */ + private void isValid() throws SerialException { + if (buf == null) { + throw new SerialException("Error: You cannot call a method on a " + + "SerialBlob instance once free() has been called."); + } + } + /** + * The identifier that assists in the serialization of this + * {@code SerialBlob} object. + */ static final long serialVersionUID = -8144641928112860441L; } diff -r a65826af2aa4 -r 701d0765f75f jdk/src/share/classes/javax/sql/rowset/serial/SerialClob.java --- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialClob.java Thu Dec 13 08:11:38 2012 +0800 +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialClob.java Wed Dec 12 20:57:45 2012 -0500 @@ -44,6 +44,11 @@ * from a SerialClob object or to locate the start of * a pattern of characters. * + *

Thread safety

+ * + *

A SerialClob is not safe for use by multiple concurrent threads. If a + * SerialClob is to be used by more than one thread then access to the SerialClob + * should be controlled by appropriate synchronization. * @author Jonathan Bruce */ public class SerialClob implements Clob, Serializable, Cloneable { @@ -180,9 +185,11 @@ * * @return a long indicating the length in characters of this * SerialClob object's array of character - * @throws SerialException if an error occurs + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object */ public long length() throws SerialException { + isValid(); return len; } @@ -194,9 +201,11 @@ * * @return a java.io.Reader object containing this * SerialClob object's data - * @throws SerialException if an error occurs + * @throws SerialException if an error occurs; + * if {@code free} had previously been called on this object */ public java.io.Reader getCharacterStream() throws SerialException { + isValid(); return (java.io.Reader) new CharArrayReader(buf); } @@ -210,13 +219,15 @@ * * @return a java.io.InputStream object containing * this SerialClob object's data - * @throws SerialException if this SerialClob object was not instantiated - * with a Clob object + * @throws SerialException if this {@code SerialClob} object was not + * instantiated with a Clob object; + * if {@code free} had previously been called on this object * @throws SQLException if there is an error accessing the - * CLOB value represented by the Clob object that was - * used to create this SerialClob object + * CLOB value represented by the Clob object + * that was used to create this SerialClob object */ public java.io.InputStream getAsciiStream() throws SerialException, SQLException { + isValid(); if (this.clob != null) { return this.clob.getAsciiStream(); } else { @@ -248,12 +259,14 @@ * this SerialClob object beginning at the * given position and containing the specified number of * consecutive characters - * @throws SerialException if either of the arguments is out of bounds + * @throws SerialException if either of the arguments is out of bounds; + * if {@code free} had previously been called on this object */ public String getSubString(long pos, int length) throws SerialException { + isValid(); if (pos < 1 || pos > this.length()) { - throw new SerialException("Invalid position in BLOB object set"); + throw new SerialException("Invalid position in SerialClob object set"); } if ((pos-1) + length > this.length()) { @@ -287,13 +300,14 @@ * -1 if the given String object is * not found or the starting position is out of bounds; position * numbering for the return value starts at 1 - * @throws SerialException if an error occurs locating the String signature - * @throws SQLException if there is an error accessing the Blob value + * @throws SerialException if the {@code free} method had been + * previously called on this object + * @throws SQLException if there is an error accessing the Clob value * from the database. */ public long position(String searchStr, long start) throws SerialException, SQLException { - + isValid(); if (start < 1 || start > len) { return -1; } @@ -332,13 +346,14 @@ * @return the position at which the given Clob * object begins in this SerialClob object, * at or after the specified starting position - * @throws SerialException if an error occurs locating the Clob signature - * @throws SQLException if there is an error accessing the Blob value + * @throws SerialException if an error occurs locating the Clob signature; + * if the {@code free} method had been previously called on this object + * @throws SQLException if there is an error accessing the Clob value * from the database */ public long position(Clob searchStr, long start) throws SerialException, SQLException { - + isValid(); return position(searchStr.getSubString(1,(int)searchStr.length()), start); } @@ -358,7 +373,8 @@ * CLOB value; if an invalid position is set; if an * invalid offset value is set; if number of bytes to be written * is greater than the SerialClob length; or the combined - * values of the length and offset is greater than the Clob buffer + * values of the length and offset is greater than the Clob buffer; + * if the {@code free} method had been previously called on this object */ public int setString(long pos, String str) throws SerialException { return (setString(pos, str, 0, str.length())); @@ -383,10 +399,12 @@ * CLOB value; if an invalid position is set; if an * invalid offset value is set; if number of bytes to be written * is greater than the SerialClob length; or the combined - * values of the length and offset is greater than the Clob buffer + * values of the length and offset is greater than the Clob buffer; + * if the {@code free} method had been previously called on this object */ public int setString(long pos, String str, int offset, int length) throws SerialException { + isValid(); String temp = str.substring(offset); char cPattern[] = temp.toCharArray(); @@ -395,7 +413,7 @@ } if (pos < 1 || pos > this.length()) { - throw new SerialException("Invalid position in BLOB object set"); + throw new SerialException("Invalid position in Clob object set"); } if ((long)(length) > origLen) { @@ -430,13 +448,15 @@ * CLOB object * @return the stream to which ASCII encoded characters can be written * @throws SerialException if SerialClob is not instantiated with a - * Clob object that supports setAsciiStream + * Clob object; + * if the {@code free} method had been previously called on this object * @throws SQLException if there is an error accessing the * CLOB value * @see #getAsciiStream */ public java.io.OutputStream setAsciiStream(long pos) throws SerialException, SQLException { + isValid(); if (this.clob != null) { return this.clob.setAsciiStream(pos); } else { @@ -460,13 +480,15 @@ * * @return a stream to which Unicode encoded characters can be written * @throws SerialException if the SerialClob is not instantiated with - * a Clob object that supports setCharacterStream + * a Clob object; + * if the {@code free} method had been previously called on this object * @throws SQLException if there is an error accessing the * CLOB value * @see #getCharacterStream */ public java.io.Writer setCharacterStream(long pos) throws SerialException, SQLException { + isValid(); if (this.clob != null) { return this.clob.setCharacterStream(pos); } else { @@ -486,33 +508,80 @@ * * @param length the length, in bytes, to which the CLOB * value should be truncated - * @throws SQLException if there is an error accessing the - * CLOB value + * @throws SerialLException if there is an error accessing the + * CLOB value; + * if the {@code free} method had been previously called on this object */ public void truncate(long length) throws SerialException { - if (length > len) { - throw new SerialException - ("Length more than what can be truncated"); - } else { - len = length; - // re-size the buffer + isValid(); + if (length > len) { + throw new SerialException + ("Length more than what can be truncated"); + } else { + len = length; + // re-size the buffer - if (len == 0) { - buf = new char[] {}; - } else { + if (len == 0) { + buf = new char[] {}; + } else { buf = (this.getSubString(1, (int)len)).toCharArray(); - } - - } + } + } } + /** + * Returns a {@code Reader} object that contains a partial + * {@code SerialClob} value, starting + * with the character specified by pos, which is length characters in length. + * + * @param pos the offset to the first character of the partial value to + * be retrieved. The first character in the {@code SerialClob} is at position 1. + * @param length the length in characters of the partial value to be retrieved. + * @return {@code Reader} through which the partial {@code SerialClob} + * value can be read. + * @throws SQLException if pos is less than 1 or if pos is greater than the + * number of characters in the {@code SerialClob} or if pos + length + * is greater than the number of characters in the {@code SerialClob}; + * @throws SerialException if the {@code free} method had been previously + * called on this object + * @since 1.6 + */ public Reader getCharacterStream(long pos, long length) throws SQLException { - throw new java.lang.UnsupportedOperationException("Not supported"); + isValid(); + if (pos < 1 || pos > len) { + throw new SerialException("Invalid position in Clob object set"); + } + + if ((pos-1) + length > len) { + throw new SerialException("Invalid position and substring length"); + } + if (length <= 0) { + throw new SerialException("Invalid length specified"); + } + return new CharArrayReader(buf, (int)pos, (int)length); } + /** + * This method frees the {@code SeriableClob} object and releases the + * resources that it holds. + * The object is invalid once the {@code free} method is called. + *

+ * If {@code free} is called multiple times, the subsequent + * calls to {@code free} are treated as a no-op. + *

+ * @throws SQLException if an error occurs releasing + * the Clob's resources + * @since 1.6 + */ public void free() throws SQLException { - throw new java.lang.UnsupportedOperationException("Not supported"); + if (buf != null) { + buf = null; + if (clob != null) { + clob.free(); + } + clob = null; + } } /** @@ -559,7 +628,7 @@ public Object clone() { try { SerialClob sc = (SerialClob) super.clone(); - sc.buf = Arrays.copyOf(buf, (int)len); + sc.buf = (buf != null) ? Arrays.copyOf(buf, (int)len) : null; sc.clob = null; return sc; } catch (CloneNotSupportedException ex) { @@ -605,7 +674,20 @@ } /** - * The identifier that assists in the serialization of this SerialClob + * Check to see if this object had previously had its {@code free} method + * called + * + * @throws SerialException + */ + private void isValid() throws SerialException { + if (buf == null) { + throw new SerialException("Error: You cannot call a method on a " + + "SerialClob instance once free() has been called."); + } + } + + /** + * The identifier that assists in the serialization of this {@code SerialClob} * object. */ static final long serialVersionUID = -1662519690087375313L; diff -r a65826af2aa4 -r 701d0765f75f jdk/src/share/classes/javax/sql/rowset/serial/SerialDatalink.java --- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialDatalink.java Thu Dec 13 08:11:38 2012 +0800 +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialDatalink.java Wed Dec 12 20:57:45 2012 -0500 @@ -42,6 +42,12 @@ *
  *      java.net.URL url = rowset.getURL(1);
  * 
+ * + *

Thread safety

+ * + * A SerialDatalink is not safe for use by multiple concurrent threads. If a + * SerialDatalink is to be used by more than one thread then access to the + * SerialDatalink should be controlled by appropriate synchronization. */ public class SerialDatalink implements Serializable, Cloneable { diff -r a65826af2aa4 -r 701d0765f75f jdk/src/share/classes/javax/sql/rowset/serial/SerialJavaObject.java --- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialJavaObject.java Thu Dec 13 08:11:38 2012 +0800 +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialJavaObject.java Wed Dec 12 20:57:45 2012 -0500 @@ -44,6 +44,12 @@ * Static or transient fields cannot be serialized; an attempt to serialize * them will result in a SerialException object being thrown. * + *

Thread safety

+ * + * A SerialJavaObject is not safe for use by multiple concurrent threads. If a + * SerialJavaObject is to be used by more than one thread then access to the + * SerialJavaObject should be controlled by appropriate synchronization. + * * @author Jonathan Bruce */ public class SerialJavaObject implements Serializable, Cloneable { diff -r a65826af2aa4 -r 701d0765f75f jdk/src/share/classes/javax/sql/rowset/serial/SerialRef.java --- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialRef.java Thu Dec 13 08:11:38 2012 +0800 +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialRef.java Wed Dec 12 20:57:45 2012 -0500 @@ -36,6 +36,13 @@ * The SerialRef class provides a constructor for * creating a SerialRef instance from a Ref * object and provides methods for getting and setting the Ref object. + * + *

Thread safety

+ * + * A SerialRef is not safe for use by multiple concurrent threads. If a + * SerialRef is to be used by more than one thread then access to the SerialRef + * should be controlled by appropriate synchronization. + * */ public class SerialRef implements Ref, Serializable, Cloneable { diff -r a65826af2aa4 -r 701d0765f75f jdk/src/share/classes/javax/sql/rowset/serial/SerialStruct.java --- a/jdk/src/share/classes/javax/sql/rowset/serial/SerialStruct.java Thu Dec 13 08:11:38 2012 +0800 +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SerialStruct.java Wed Dec 12 20:57:45 2012 -0500 @@ -50,6 +50,13 @@ * an instance from a Struct object, a method for retrieving * the SQL type name of the SQL structured type in the database, and methods * for retrieving its attribute values. + * + *

Thread safety

+ * + * A SerialStruct is not safe for use by multiple concurrent threads. If a + * SerialStruct is to be used by more than one thread then access to the + * SerialStruct should be controlled by appropriate synchronization. + * */ public class SerialStruct implements Struct, Serializable, Cloneable {