feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import java.io.*;
import java.math.*;
/**
* The standard interface that all standard implementations of
* <code>FilteredRowSet</code> must implement. The <code>FilteredRowSetImpl</code> class
* provides the reference implementation which may be extended if required.
* Alternatively, a vendor is free to implement its own version
* by implementing this interface.
*
* <h3>1.0 Background</h3>
*
* There are occasions when a <code>RowSet</code> object has a need to provide a degree
* of filtering to its contents. One possible solution is to provide
* a query language for all standard <code>RowSet</code> implementations; however,
* this is an impractical approach for lightweight components such as disconnected
* <code>RowSet</code>
* objects. The <code>FilteredRowSet</code> interface seeks to address this need
* without supplying a heavyweight query language along with the processing that
* such a query language would require.
* <p>
* A JDBC <code>FilteredRowSet</code> standard implementation implements the
* <code>RowSet</code> interfaces and extends the
* <code>CachedRowSet</code>&trade; class. The
* <code>CachedRowSet</code> class provides a set of protected cursor manipulation
* methods, which a <code>FilteredRowSet</code> implementation can override
* to supply filtering support.
*
* <h3>2.0 Predicate Sharing</h3>
*
* If a <code>FilteredRowSet</code> implementation is shared using the
* inherited <code>createShared</code> method in parent interfaces, the
* <code>Predicate</code> should be shared without modification by all
* <code>FilteredRowSet</code> instance clones.
*
* <h3>3.0 Usage</h3>
* <p>
* By implementing a <code>Predicate</code> (see example in <a href="Predicate.html">Predicate</a>
* class JavaDoc), a <code>FilteredRowSet</code> could then be used as described
* below.
*
* <pre>
* {@code
* FilteredRowSet frs = new FilteredRowSetImpl();
* frs.populate(rs);
*
* Range name = new Range("Alpha", "Bravo", "columnName");
* frs.setFilter(name);
*
* frs.next() // only names from "Alpha" to "Bravo" will be returned
* }
* </pre>
* In the example above, we initialize a <code>Range</code> object which
* implements the <code>Predicate</code> interface. This object expresses
* the following constraints: All rows outputted or modified from this
* <code>FilteredRowSet</code> object must fall between the values 'Alpha' and
* 'Bravo' both values inclusive, in the column 'columnName'. If a filter is
* applied to a <code>FilteredRowSet</code> object that contains no data that
* falls within the range of the filter, no rows are returned.
* <p>
* This framework allows multiple classes implementing predicates to be
* used in combination to achieved the required filtering result with
* out the need for query language processing.
*
* <h3>4.0 Updating a <code>FilteredRowSet</code> Object</h3>
* The predicate set on a <code>FilteredRowSet</code> object
* applies a criterion on all rows in a
* <code>RowSet</code> object to manage a subset of rows in a <code>RowSet</code>
* object. This criterion governs the subset of rows that are visible and also
* defines which rows can be modified, deleted or inserted.
* <p>
* Therefore, the predicate set on a <code>FilteredRowSet</code> object must be
* considered as bi-directional and the set criterion as the gating mechanism
* for all views and updates to the <code>FilteredRowSet</code> object. Any attempt
* to update the <code>FilteredRowSet</code> that violates the criterion will
* result in a <code>SQLException</code> object being thrown.
* <p>
* The <code>FilteredRowSet</code> range criterion can be modified by applying
* a new <code>Predicate</code> object to the <code>FilteredRowSet</code>
* instance at any time. This is possible if no additional references to the
* <code>FilteredRowSet</code> object are detected. A new filter has has an
* immediate effect on criterion enforcement within the
* <code>FilteredRowSet</code> object, and all subsequent views and updates will be
* subject to similar enforcement.
*
* <h3>5.0 Behavior of Rows Outside the Filter</h3>
* Rows that fall outside of the filter set on a <code>FilteredRowSet</code>
* object cannot be modified until the filter is removed or a
* new filter is applied.
* <p>
* Furthermore, only rows that fall within the bounds of a filter will be
* synchronized with the data source.
*
* @author Jonathan Bruce
*/
public interface FilteredRowSet extends WebRowSet {
/**
* Applies the given <code>Predicate</code> object to this
* <code>FilteredRowSet</code>
* object. The filter applies controls both to inbound and outbound views,
* constraining which rows are visible and which
* rows can be manipulated.
* <p>
* A new <code>Predicate</code> object may be set at any time. This has the
* effect of changing constraints on the <code>RowSet</code> object's data.
* In addition, modifying the filter at runtime presents issues whereby
* multiple components may be operating on one <code>FilteredRowSet</code> object.
* Application developers must take responsibility for managing multiple handles
* to <code>FilteredRowSet</code> objects when their underling <code>Predicate</code>
* objects change.
*
* @param p a <code>Predicate</code> object defining the filter for this
* <code>FilteredRowSet</code> object. Setting a <b>null</b> value
* will clear the predicate, allowing all rows to become visible.
*
* @throws SQLException if an error occurs when setting the
* <code>Predicate</code> object
*/
public void setFilter(Predicate p) throws SQLException;
/**
* Retrieves the active filter for this <code>FilteredRowSet</code> object.
*
* @return p the <code>Predicate</code> for this <code>FilteredRowSet</code>
* object; <code>null</code> if no filter has been set.
*/
public Predicate getFilter() ;
}

View File

@@ -0,0 +1,289 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import java.io.*;
import java.math.*;
import java.io.*;
/**
* The standard interface that all standard implementations of
* <code>JdbcRowSet</code> must implement.
*
* <h3>1.0 Overview</h3>
* A wrapper around a <code>ResultSet</code> object that makes it possible
* to use the result set as a JavaBeans&trade;
* component. Thus, a <code>JdbcRowSet</code> object can be one of the Beans that
* a tool makes available for composing an application. Because
* a <code>JdbcRowSet</code> is a connected rowset, that is, it continually
* maintains its connection to a database using a JDBC technology-enabled
* driver, it also effectively makes the driver a JavaBeans component.
* <P>
* Because it is always connected to its database, an instance of
* <code>JdbcRowSet</code>
* can simply take calls invoked on it and in turn call them on its
* <code>ResultSet</code> object. As a consequence, a result set can, for
* example, be a component in a Swing application.
* <P>
* Another advantage of a <code>JdbcRowSet</code> object is that it can be
* used to make a <code>ResultSet</code> object scrollable and updatable. All
* <code>RowSet</code> objects are by default scrollable and updatable. If
* the driver and database being used do not support scrolling and/or updating
* of result sets, an application can populate a <code>JdbcRowSet</code> object
* with the data of a <code>ResultSet</code> object and then operate on the
* <code>JdbcRowSet</code> object as if it were the <code>ResultSet</code>
* object.
*
* <h3>2.0 Creating a <code>JdbcRowSet</code> Object</h3>
* The reference implementation of the <code>JdbcRowSet</code> interface,
* <code>JdbcRowSetImpl</code>, provides an implementation of
* the default constructor. A new instance is initialized with
* default values, which can be set with new values as needed. A
* new instance is not really functional until its <code>execute</code>
* method is called. In general, this method does the following:
* <UL>
* <LI> establishes a connection with a database
* <LI> creates a <code>PreparedStatement</code> object and sets any of its
* placeholder parameters
* <LI> executes the statement to create a <code>ResultSet</code> object
* </UL>
* If the <code>execute</code> method is successful, it will set the
* appropriate private <code>JdbcRowSet</code> fields with the following:
* <UL>
* <LI> a <code>Connection</code> object -- the connection between the rowset
* and the database
* <LI> a <code>PreparedStatement</code> object -- the query that produces
* the result set
* <LI> a <code>ResultSet</code> object -- the result set that the rowset's
* command produced and that is being made, in effect, a JavaBeans
* component
* </UL>
* If these fields have not been set, meaning that the <code>execute</code>
* method has not executed successfully, no methods other than
* <code>execute</code> and <code>close</code> may be called on the
* rowset. All other public methods will throw an exception.
* <P>
* Before calling the <code>execute</code> method, however, the command
* and properties needed for establishing a connection must be set.
* The following code fragment creates a <code>JdbcRowSetImpl</code> object,
* sets the command and connection properties, sets the placeholder parameter,
* and then invokes the method <code>execute</code>.
* <PRE>
* JdbcRowSetImpl jrs = new JdbcRowSetImpl();
* jrs.setCommand("SELECT * FROM TITLES WHERE TYPE = ?");
* jrs.setURL("jdbc:myDriver:myAttribute");
* jrs.setUsername("cervantes");
* jrs.setPassword("sancho");
* jrs.setString(1, "BIOGRAPHY");
* jrs.execute();
* </PRE>
* The variable <code>jrs</code> now represents an instance of
* <code>JdbcRowSetImpl</code> that is a thin wrapper around the
* <code>ResultSet</code> object containing all the rows in the
* table <code>TITLES</code> where the type of book is biography.
* At this point, operations called on <code>jrs</code> will
* affect the rows in the result set, which is effectively a JavaBeans
* component.
* <P>
* The implementation of the <code>RowSet</code> method <code>execute</code> in the
* <code>JdbcRowSet</code> reference implementation differs from that in the
* <code>CachedRowSet</code>&trade;
* reference implementation to account for the different
* requirements of connected and disconnected <code>RowSet</code> objects.
* <p>
*
* @author Jonathan Bruce
*/
public interface JdbcRowSet extends RowSet, Joinable {
/**
* Retrieves a <code>boolean</code> indicating whether rows marked
* for deletion appear in the set of current rows. If <code>true</code> is
* returned, deleted rows are visible with the current rows. If
* <code>false</code> is returned, rows are not visible with the set of
* current rows. The default value is <code>false</code>.
* <P>
* Standard rowset implementations may choose to restrict this behavior
* for security considerations or for certain deployment
* scenarios. The visibility of deleted rows is implementation-defined
* and does not represent standard behavior.
* <P>
* Note: Allowing deleted rows to remain visible complicates the behavior
* of some standard JDBC <code>RowSet</code> implementations methods.
* However, most rowset users can simply ignore this extra detail because
* only very specialized applications will likely want to take advantage of
* this feature.
*
* @return <code>true</code> if deleted rows are visible;
* <code>false</code> otherwise
* @exception SQLException if a rowset implementation is unable to
* to determine whether rows marked for deletion remain visible
* @see #setShowDeleted
*/
public boolean getShowDeleted() throws SQLException;
/**
* Sets the property <code>showDeleted</code> to the given
* <code>boolean</code> value. This property determines whether
* rows marked for deletion continue to appear in the set of current rows.
* If the value is set to <code>true</code>, deleted rows are immediately
* visible with the set of current rows. If the value is set to
* <code>false</code>, the deleted rows are set as invisible with the
* current set of rows.
* <P>
* Standard rowset implementations may choose to restrict this behavior
* for security considerations or for certain deployment
* scenarios. This is left as implementation-defined and does not
* represent standard behavior.
*
* @param b <code>true</code> if deleted rows should be shown;
* <code>false</code> otherwise
* @exception SQLException if a rowset implementation is unable to
* to reset whether deleted rows should be visible
* @see #getShowDeleted
*/
public void setShowDeleted(boolean b) throws SQLException;
/**
* Retrieves the first warning reported by calls on this <code>JdbcRowSet</code>
* object.
* If a second warning was reported on this <code>JdbcRowSet</code> object,
* it will be chained to the first warning and can be retrieved by
* calling the method <code>RowSetWarning.getNextWarning</code> on the
* first warning. Subsequent warnings on this <code>JdbcRowSet</code>
* object will be chained to the <code>RowSetWarning</code> objects
* returned by the method <code>RowSetWarning.getNextWarning</code>.
*
* The warning chain is automatically cleared each time a new row is read.
* This method may not be called on a <code>RowSet</code> object
* that has been closed;
* doing so will cause an <code>SQLException</code> to be thrown.
* <P>
* Because it is always connected to its data source, a <code>JdbcRowSet</code>
* object can rely on the presence of active
* <code>Statement</code>, <code>Connection</code>, and <code>ResultSet</code>
* instances. This means that applications can obtain additional
* <code>SQLWarning</code>
* notifications by calling the <code>getNextWarning</code> methods that
* they provide.
* Disconnected <code>Rowset</code> objects, such as a
* <code>CachedRowSet</code> object, do not have access to
* these <code>getNextWarning</code> methods.
*
* @return the first <code>RowSetWarning</code>
* object reported on this <code>JdbcRowSet</code> object
* or <code>null</code> if there are none
* @throws SQLException if this method is called on a closed
* <code>JdbcRowSet</code> object
* @see RowSetWarning
*/
public RowSetWarning getRowSetWarnings() throws SQLException;
/**
* Each <code>JdbcRowSet</code> contains a <code>Connection</code> object from
* the <code>ResultSet</code> or JDBC properties passed to it's constructors.
* This method wraps the <code>Connection</code> commit method to allow flexible
* auto commit or non auto commit transactional control support.
* <p>
* Makes all changes made since the previous commit/rollback permanent
* and releases any database locks currently held by this Connection
* object. This method should be used only when auto-commit mode has
* been disabled.
*
* @throws SQLException if a database access error occurs or this
* Connection object within this <code>JdbcRowSet</code> is in auto-commit mode
* @see java.sql.Connection#setAutoCommit
*/
public void commit() throws SQLException;
/**
* Each <code>JdbcRowSet</code> contains a <code>Connection</code> object from
* the original <code>ResultSet</code> or JDBC properties passed to it. This
* method wraps the <code>Connection</code>'s <code>getAutoCommit</code> method
* to allow an application to determine the <code>JdbcRowSet</code> transaction
* behavior.
* <p>
* Sets this connection's auto-commit mode to the given state. If a
* connection is in auto-commit mode, then all its SQL statements will
* be executed and committed as individual transactions. Otherwise, its
* SQL statements are grouped into transactions that are terminated by a
* call to either the method commit or the method rollback. By default,
* new connections are in auto-commit mode.
*
* @return {@code true} if auto-commit is enabled; {@code false} otherwise
* @throws SQLException if a database access error occurs
* @see java.sql.Connection#getAutoCommit()
*/
public boolean getAutoCommit() throws SQLException;
/**
* Each <code>JdbcRowSet</code> contains a <code>Connection</code> object from
* the original <code>ResultSet</code> or JDBC properties passed to it. This
* method wraps the <code>Connection</code>'s <code>getAutoCommit</code> method
* to allow an application to set the <code>JdbcRowSet</code> transaction behavior.
* <p>
* Sets the current auto-commit mode for this <code>Connection</code> object.
* @param autoCommit {@code true} to enable auto-commit; {@code false} to
* disable auto-commit
* @throws SQLException if a database access error occurs
* @see java.sql.Connection#setAutoCommit(boolean)
*/
public void setAutoCommit(boolean autoCommit) throws SQLException;
/**
* Each <code>JdbcRowSet</code> contains a <code>Connection</code> object from
* the original <code>ResultSet</code> or JDBC properties passed to it.
* Undoes all changes made in the current transaction and releases any
* database locks currently held by this <code>Connection</code> object. This method
* should be used only when auto-commit mode has been disabled.
*
* @throws SQLException if a database access error occurs or this <code>Connection</code>
* object within this <code>JdbcRowSet</code> is in auto-commit mode.
* @see #rollback(Savepoint)
*/
public void rollback() throws SQLException;
/**
* Each <code>JdbcRowSet</code> contains a <code>Connection</code> object from
* the original <code>ResultSet</code> or JDBC properties passed to it.
* Undoes all changes made in the current transaction to the last set savepoint
* and releases any database locks currently held by this <code>Connection</code>
* object. This method should be used only when auto-commit mode has been disabled.
* @param s The {@code Savepoint} to rollback to
* @throws SQLException if a database access error occurs or this <code>Connection</code>
* object within this <code>JdbcRowSet</code> is in auto-commit mode.
* @see #rollback
*/
public void rollback(Savepoint s) throws SQLException;
}

View File

@@ -0,0 +1,536 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import java.io.*;
import java.math.*;
import java.util.*;
import javax.sql.rowset.*;
/**
* The <code>JoinRowSet</code> interface provides a mechanism for combining related
* data from different <code>RowSet</code> objects into one <code>JoinRowSet</code>
* object, which represents an SQL <code>JOIN</code>.
* In other words, a <code>JoinRowSet</code> object acts as a
* container for the data from <code>RowSet</code> objects that form an SQL
* <code>JOIN</code> relationship.
* <P>
* The <code>Joinable</code> interface provides the methods for setting,
* retrieving, and unsetting a match column, the basis for
* establishing an SQL <code>JOIN</code> relationship. The match column may
* alternatively be set by supplying it to the appropriate version of the
* <code>JointRowSet</code> method <code>addRowSet</code>.
*
* <h3>1.0 Overview</h3>
* Disconnected <code>RowSet</code> objects (<code>CachedRowSet</code> objects
* and implementations extending the <code>CachedRowSet</code> interface)
* do not have a standard way to establish an SQL <code>JOIN</code> between
* <code>RowSet</code> objects without the expensive operation of
* reconnecting to the data source. The <code>JoinRowSet</code>
* interface is specifically designed to address this need.
* <P>
* Any <code>RowSet</code> object
* can be added to a <code>JoinRowSet</code> object to become
* part of an SQL <code>JOIN</code> relationship. This means that both connected
* and disconnected <code>RowSet</code> objects can be part of a <code>JOIN</code>.
* <code>RowSet</code> objects operating in a connected environment
* (<code>JdbcRowSet</code> objects) are
* encouraged to use the database to which they are already
* connected to establish SQL <code>JOIN</code> relationships between
* tables directly. However, it is possible for a
* <code>JdbcRowSet</code> object to be added to a <code>JoinRowSet</code> object
* if necessary.
* <P>
* Any number of <code>RowSet</code> objects can be added to an
* instance of <code>JoinRowSet</code> provided that they
* can be related in an SQL <code>JOIN</code>.
* By definition, the SQL <code>JOIN</code> statement is used to
* combine the data contained in two or more relational database tables based
* upon a common attribute. The <code>Joinable</code> interface provides the methods
* for establishing a common attribute, which is done by setting a
* <i>match column</i>. The match column commonly coincides with
* the primary key, but there is
* no requirement that the match column be the same as the primary key.
* By establishing and then enforcing column matches,
* a <code>JoinRowSet</code> object establishes <code>JOIN</code> relationships
* between <code>RowSet</code> objects without the assistance of an available
* relational database.
* <P>
* The type of <code>JOIN</code> to be established is determined by setting
* one of the <code>JoinRowSet</code> constants using the method
* <code>setJoinType</code>. The following SQL <code>JOIN</code> types can be set:
* <UL>
* <LI><code>CROSS_JOIN</code>
* <LI><code>FULL_JOIN</code>
* <LI><code>INNER_JOIN</code> - the default if no <code>JOIN</code> type has been set
* <LI><code>LEFT_OUTER_JOIN</code>
* <LI><code>RIGHT_OUTER_JOIN</code>
* </UL>
* Note that if no type is set, the <code>JOIN</code> will automatically be an
* inner join. The comments for the fields in the
* <code>JoinRowSet</code> interface explain these <code>JOIN</code> types, which are
* standard SQL <code>JOIN</code> types.
*
* <h3>2.0 Using a <code>JoinRowSet</code> Object for Creating a <code>JOIN</code></h3>
* When a <code>JoinRowSet</code> object is created, it is empty.
* The first <code>RowSet</code> object to be added becomes the basis for the
* <code>JOIN</code> relationship.
* Applications must determine which column in each of the
* <code>RowSet</code> objects to be added to the <code>JoinRowSet</code> object
* should be the match column. All of the
* <code>RowSet</code> objects must contain a match column, and the values in
* each match column must be ones that can be compared to values in the other match
* columns. The columns do not have to have the same name, though they often do,
* and they do not have to store the exact same data type as long as the data types
* can be compared.
* <P>
* A match column can be be set in two ways:
* <ul>
* <li>By calling the <code>Joinable</code> method <code>setMatchColumn</code><br>
* This is the only method that can set the match column before a <code>RowSet</code>
* object is added to a <code>JoinRowSet</code> object. The <code>RowSet</code> object
* must have implemented the <code>Joinable</code> interface in order to use the method
* <code>setMatchColumn</code>. Once the match column value
* has been set, this method can be used to reset the match column at any time.
* <li>By calling one of the versions of the <code>JoinRowSet</code> method
* <code>addRowSet</code> that takes a column name or number (or an array of
* column names or numbers)<BR>
* Four of the five <code>addRowSet</code> methods take a match column as a parameter.
* These four methods set or reset the match column at the time a <code>RowSet</code>
* object is being added to a <code>JoinRowSet</code> object.
* </ul>
* <h3>3.0 Sample Usage</h3>
* <p>
* The following code fragment adds two <code>CachedRowSet</code>
* objects to a <code>JoinRowSet</code> object. Note that in this example,
* no SQL <code>JOIN</code> type is set, so the default <code>JOIN</code> type,
* which is <i>INNER_JOIN</i>, is established.
* <p>
* In the following code fragment, the table <code>EMPLOYEES</code>, whose match
* column is set to the first column (<code>EMP_ID</code>), is added to the
* <code>JoinRowSet</code> object <i>jrs</i>. Then
* the table <code>ESSP_BONUS_PLAN</code>, whose match column is likewise
* the <code>EMP_ID</code> column, is added. When this second
* table is added to <i>jrs</i>, only the rows in
* <code>ESSP_BONUS_PLAN</code> whose <code>EMP_ID</code> value matches an
* <code>EMP_ID</code> value in the <code>EMPLOYEES</code> table are added.
* In this case, everyone in the bonus plan is an employee, so all of the rows
* in the table <code>ESSP_BONUS_PLAN</code> are added to the <code>JoinRowSet</code>
* object. In this example, both <code>CachedRowSet</code> objects being added
* have implemented the <code>Joinable</code> interface and can therefore call
* the <code>Joinable</code> method <code>setMatchColumn</code>.
* <PRE>
* JoinRowSet jrs = new JoinRowSetImpl();
*
* ResultSet rs1 = stmt.executeQuery("SELECT * FROM EMPLOYEES");
* CachedRowSet empl = new CachedRowSetImpl();
* empl.populate(rs1);
* empl.setMatchColumn(1);
* jrs.addRowSet(empl);
*
* ResultSet rs2 = stmt.executeQuery("SELECT * FROM ESSP_BONUS_PLAN");
* CachedRowSet bonus = new CachedRowSetImpl();
* bonus.populate(rs2);
* bonus.setMatchColumn(1); // EMP_ID is the first column
* jrs.addRowSet(bonus);
* </PRE>
* <P>
* At this point, <i>jrs</i> is an inside JOIN of the two <code>RowSet</code> objects
* based on their <code>EMP_ID</code> columns. The application can now browse the
* combined data as if it were browsing one single <code>RowSet</code> object.
* Because <i>jrs</i> is itself a <code>RowSet</code> object, an application can
* navigate or modify it using <code>RowSet</code> methods.
* <PRE>
* jrs.first();
* int employeeID = jrs.getInt(1);
* String employeeName = jrs.getString(2);
* </PRE>
* <P>
* Note that because the SQL <code>JOIN</code> must be enforced when an application
* adds a second or subsequent <code>RowSet</code> object, there
* may be an initial degradation in performance while the <code>JOIN</code> is
* being performed.
* <P>
* The following code fragment adds an additional <code>CachedRowSet</code> object.
* In this case, the match column (<code>EMP_ID</code>) is set when the
* <code>CachedRowSet</code> object is added to the <code>JoinRowSet</code> object.
* <PRE>
* ResultSet rs3 = stmt.executeQuery("SELECT * FROM 401K_CONTRIB");
* CachedRowSet fourO1k = new CachedRowSetImpl();
* four01k.populate(rs3);
* jrs.addRowSet(four01k, 1);
* </PRE>
* <P>
* The <code>JoinRowSet</code> object <i>jrs</i> now contains values from all three
* tables. The data in each row in <i>four01k</i> in which the value for the
* <code>EMP_ID</code> column matches a value for the <code>EMP_ID</code> column
* in <i>jrs</i> has been added to <i>jrs</i>.
*
* <h3>4.0 <code>JoinRowSet</code> Methods</h3>
* The <code>JoinRowSet</code> interface supplies several methods for adding
* <code>RowSet</code> objects and for getting information about the
* <code>JoinRowSet</code> object.
* <UL>
* <LI>Methods for adding one or more <code>RowSet</code> objects<BR>
* These methods allow an application to add one <code>RowSet</code> object
* at a time or to add multiple <code>RowSet</code> objects at one time. In
* either case, the methods may specify the match column for each
* <code>RowSet</code> object being added.
* <LI>Methods for getting information<BR>
* One method retrieves the <code>RowSet</code> objects in the
* <code>JoinRowSet</code> object, and another method retrieves the
* <code>RowSet</code> names. A third method retrieves either the SQL
* <code>WHERE</code> clause used behind the scenes to form the
* <code>JOIN</code> or a text description of what the <code>WHERE</code>
* clause does.
* <LI>Methods related to the type of <code>JOIN</code><BR>
* One method sets the <code>JOIN</code> type, and five methods find out whether
* the <code>JoinRowSet</code> object supports a given type.
* <LI>A method to make a separate copy of the <code>JoinRowSet</code> object<BR>
* This method creates a copy that can be persisted to the data source.
* </UL>
*
*/
public interface JoinRowSet extends WebRowSet {
/**
* Adds the given <code>RowSet</code> object to this <code>JoinRowSet</code>
* object. If the <code>RowSet</code> object
* is the first to be added to this <code>JoinRowSet</code>
* object, it forms the basis of the <code>JOIN</code> relationship to be
* established.
* <P>
* This method should be used only when the given <code>RowSet</code>
* object already has a match column that was set with the <code>Joinable</code>
* method <code>setMatchColumn</code>.
* <p>
* Note: A <code>Joinable</code> object is any <code>RowSet</code> object
* that has implemented the <code>Joinable</code> interface.
*
* @param rowset the <code>RowSet</code> object that is to be added to this
* <code>JoinRowSet</code> object; it must implement the
* <code>Joinable</code> interface and have a match column set
* @throws SQLException if (1) an empty rowset is added to the to this
* <code>JoinRowSet</code> object, (2) a match column has not been
* set for <i>rowset</i>, or (3) <i>rowset</i>
* violates the active <code>JOIN</code>
* @see Joinable#setMatchColumn
*/
public void addRowSet(Joinable rowset) throws SQLException;
/**
* Adds the given <code>RowSet</code> object to this <code>JoinRowSet</code>
* object and sets the designated column as the match column for
* the <code>RowSet</code> object. If the <code>RowSet</code> object
* is the first to be added to this <code>JoinRowSet</code>
* object, it forms the basis of the <code>JOIN</code> relationship to be
* established.
* <P>
* This method should be used when <i>RowSet</i> does not already have a match
* column set.
*
* @param rowset the <code>RowSet</code> object that is to be added to this
* <code>JoinRowSet</code> object; it may implement the
* <code>Joinable</code> interface
* @param columnIdx an <code>int</code> that identifies the column to become the
* match column
* @throws SQLException if (1) <i>rowset</i> is an empty rowset or
* (2) <i>rowset</i> violates the active <code>JOIN</code>
* @see Joinable#unsetMatchColumn
*/
public void addRowSet(RowSet rowset, int columnIdx) throws SQLException;
/**
* Adds <i>rowset</i> to this <code>JoinRowSet</code> object and
* sets the designated column as the match column. If <i>rowset</i>
* is the first to be added to this <code>JoinRowSet</code>
* object, it forms the basis for the <code>JOIN</code> relationship to be
* established.
* <P>
* This method should be used when the given <code>RowSet</code> object
* does not already have a match column.
*
* @param rowset the <code>RowSet</code> object that is to be added to this
* <code>JoinRowSet</code> object; it may implement the
* <code>Joinable</code> interface
* @param columnName the <code>String</code> object giving the name of the
* column to be set as the match column
* @throws SQLException if (1) <i>rowset</i> is an empty rowset or
* (2) the match column for <i>rowset</i> does not satisfy the
* conditions of the <code>JOIN</code>
*/
public void addRowSet(RowSet rowset,
String columnName) throws SQLException;
/**
* Adds one or more <code>RowSet</code> objects contained in the given
* array of <code>RowSet</code> objects to this <code>JoinRowSet</code>
* object and sets the match column for
* each of the <code>RowSet</code> objects to the match columns
* in the given array of column indexes. The first element in
* <i>columnIdx</i> is set as the match column for the first
* <code>RowSet</code> object in <i>rowset</i>, the second element of
* <i>columnIdx</i> is set as the match column for the second element
* in <i>rowset</i>, and so on.
* <P>
* The first <code>RowSet</code> object added to this <code>JoinRowSet</code>
* object forms the basis for the <code>JOIN</code> relationship.
* <P>
* This method should be used when the given <code>RowSet</code> object
* does not already have a match column.
*
* @param rowset an array of one or more <code>RowSet</code> objects
* to be added to the <code>JOIN</code>; it may implement the
* <code>Joinable</code> interface
* @param columnIdx an array of <code>int</code> values indicating the index(es)
* of the columns to be set as the match columns for the <code>RowSet</code>
* objects in <i>rowset</i>
* @throws SQLException if (1) an empty rowset is added to this
* <code>JoinRowSet</code> object, (2) a match column is not set
* for a <code>RowSet</code> object in <i>rowset</i>, or (3)
* a <code>RowSet</code> object being added violates the active
* <code>JOIN</code>
*/
public void addRowSet(RowSet[] rowset,
int[] columnIdx) throws SQLException;
/**
* Adds one or more <code>RowSet</code> objects contained in the given
* array of <code>RowSet</code> objects to this <code>JoinRowSet</code>
* object and sets the match column for
* each of the <code>RowSet</code> objects to the match columns
* in the given array of column names. The first element in
* <i>columnName</i> is set as the match column for the first
* <code>RowSet</code> object in <i>rowset</i>, the second element of
* <i>columnName</i> is set as the match column for the second element
* in <i>rowset</i>, and so on.
* <P>
* The first <code>RowSet</code> object added to this <code>JoinRowSet</code>
* object forms the basis for the <code>JOIN</code> relationship.
* <P>
* This method should be used when the given <code>RowSet</code> object(s)
* does not already have a match column.
*
* @param rowset an array of one or more <code>RowSet</code> objects
* to be added to the <code>JOIN</code>; it may implement the
* <code>Joinable</code> interface
* @param columnName an array of <code>String</code> values indicating the
* names of the columns to be set as the match columns for the
* <code>RowSet</code> objects in <i>rowset</i>
* @throws SQLException if (1) an empty rowset is added to this
* <code>JoinRowSet</code> object, (2) a match column is not set
* for a <code>RowSet</code> object in <i>rowset</i>, or (3)
* a <code>RowSet</code> object being added violates the active
* <code>JOIN</code>
*/
public void addRowSet(RowSet[] rowset,
String[] columnName) throws SQLException;
/**
* Returns a <code>Collection</code> object containing the
* <code>RowSet</code> objects that have been added to this
* <code>JoinRowSet</code> object.
* This should return the 'n' number of RowSet contained
* within the <code>JOIN</code> and maintain any updates that have occurred while in
* this union.
*
* @return a <code>Collection</code> object consisting of the
* <code>RowSet</code> objects added to this <code>JoinRowSet</code>
* object
* @throws SQLException if an error occurs generating the
* <code>Collection</code> object to be returned
*/
public Collection<?> getRowSets() throws java.sql.SQLException;
/**
* Returns a <code>String</code> array containing the names of the
* <code>RowSet</code> objects added to this <code>JoinRowSet</code>
* object.
*
* @return a <code>String</code> array of the names of the
* <code>RowSet</code> objects in this <code>JoinRowSet</code>
* object
* @throws SQLException if an error occurs retrieving the names of
* the <code>RowSet</code> objects
* @see CachedRowSet#setTableName
*/
public String[] getRowSetNames() throws java.sql.SQLException;
/**
* Creates a new <code>CachedRowSet</code> object containing the
* data in this <code>JoinRowSet</code> object, which can be saved
* to a data source using the <code>SyncProvider</code> object for
* the <code>CachedRowSet</code> object.
* <P>
* If any updates or modifications have been applied to the JoinRowSet
* the CachedRowSet returned by the method will not be able to persist
* it's changes back to the originating rows and tables in the
* in the datasource. The CachedRowSet instance returned should not
* contain modification data and it should clear all properties of
* it's originating SQL statement. An application should reset the
* SQL statement using the <code>RowSet.setCommand</code> method.
* <p>
* In order to allow changes to be persisted back to the datasource
* to the originating tables, the <code>acceptChanges</code> method
* should be used and called on a JoinRowSet object instance. Implementations
* can leverage the internal data and update tracking in their
* implementations to interact with the SyncProvider to persist any
* changes.
*
* @return a CachedRowSet containing the contents of the JoinRowSet
* @throws SQLException if an error occurs assembling the CachedRowSet
* object
* @see javax.sql.RowSet
* @see javax.sql.rowset.CachedRowSet
* @see javax.sql.rowset.spi.SyncProvider
*/
public CachedRowSet toCachedRowSet() throws java.sql.SQLException;
/**
* Indicates if CROSS_JOIN is supported by a JoinRowSet
* implementation
*
* @return true if the CROSS_JOIN is supported; false otherwise
*/
public boolean supportsCrossJoin();
/**
* Indicates if INNER_JOIN is supported by a JoinRowSet
* implementation
*
* @return true is the INNER_JOIN is supported; false otherwise
*/
public boolean supportsInnerJoin();
/**
* Indicates if LEFT_OUTER_JOIN is supported by a JoinRowSet
* implementation
*
* @return true is the LEFT_OUTER_JOIN is supported; false otherwise
*/
public boolean supportsLeftOuterJoin();
/**
* Indicates if RIGHT_OUTER_JOIN is supported by a JoinRowSet
* implementation
*
* @return true is the RIGHT_OUTER_JOIN is supported; false otherwise
*/
public boolean supportsRightOuterJoin();
/**
* Indicates if FULL_JOIN is supported by a JoinRowSet
* implementation
*
* @return true is the FULL_JOIN is supported; false otherwise
*/
public boolean supportsFullJoin();
/**
* Allow the application to adjust the type of <code>JOIN</code> imposed
* on tables contained within the JoinRowSet object instance.
* Implementations should throw a SQLException if they do
* not support a given <code>JOIN</code> type.
*
* @param joinType the standard JoinRowSet.XXX static field definition
* of a SQL <code>JOIN</code> to re-configure a JoinRowSet instance on
* the fly.
* @throws SQLException if an unsupported <code>JOIN</code> type is set
* @see #getJoinType
*/
public void setJoinType(int joinType) throws SQLException;
/**
* Return a SQL-like description of the WHERE clause being used
* in a JoinRowSet object. An implementation can describe
* the WHERE clause of the SQL <code>JOIN</code> by supplying a SQL
* strings description of <code>JOIN</code> or provide a textual
* description to assist applications using a <code>JoinRowSet</code>
*
* @return whereClause a textual or SQL description of the logical
* WHERE clause used in the JoinRowSet instance
* @throws SQLException if an error occurs in generating a representation
* of the WHERE clause.
*/
public String getWhereClause() throws SQLException;
/**
* Returns a <code>int</code> describing the set SQL <code>JOIN</code> type
* governing this JoinRowSet instance. The returned type will be one of
* standard JoinRowSet types: <code>CROSS_JOIN</code>, <code>INNER_JOIN</code>,
* <code>LEFT_OUTER_JOIN</code>, <code>RIGHT_OUTER_JOIN</code> or
* <code>FULL_JOIN</code>.
*
* @return joinType one of the standard JoinRowSet static field
* definitions of a SQL <code>JOIN</code>. <code>JoinRowSet.INNER_JOIN</code>
* is returned as the default <code>JOIN</code> type is no type has been
* explicitly set.
* @throws SQLException if an error occurs determining the SQL <code>JOIN</code>
* type supported by the JoinRowSet instance.
* @see #setJoinType
*/
public int getJoinType() throws SQLException;
/**
* An ANSI-style <code>JOIN</code> providing a cross product of two tables
*/
public static int CROSS_JOIN = 0;
/**
* An ANSI-style <code>JOIN</code> providing a inner join between two tables. Any
* unmatched rows in either table of the join should be discarded.
*/
public static int INNER_JOIN = 1;
/**
* An ANSI-style <code>JOIN</code> providing a left outer join between two
* tables. In SQL, this is described where all records should be
* returned from the left side of the JOIN statement.
*/
public static int LEFT_OUTER_JOIN = 2;
/**
* An ANSI-style <code>JOIN</code> providing a right outer join between
* two tables. In SQL, this is described where all records from the
* table on the right side of the JOIN statement even if the table
* on the left has no matching record.
*/
public static int RIGHT_OUTER_JOIN = 3;
/**
* An ANSI-style <code>JOIN</code> providing a a full JOIN. Specifies that all
* rows from either table be returned regardless of matching
* records on the other table.
*/
public static int FULL_JOIN = 4;
}

View File

@@ -0,0 +1,291 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import java.sql.SQLException;
/**
* <h3>1.0 Background</h3>
* The <code>Joinable</code> interface provides the methods for getting and
* setting a match column, which is the basis for forming the SQL <code>JOIN</code>
* formed by adding <code>RowSet</code> objects to a <code>JoinRowSet</code>
* object.
* <P>
* Any standard <code>RowSet</code> implementation <b>may</b> implement
* the <code>Joinable</code> interface in order to be
* added to a <code>JoinRowSet</code> object. Implementing this interface gives
* a <code>RowSet</code> object the ability to use <code>Joinable</code> methods,
* which set, retrieve, and get information about match columns. An
* application may add a
* <code>RowSet</code> object that has not implemented the <code>Joinable</code>
* interface to a <code>JoinRowSet</code> object, but to do so it must use one
* of the <code>JoinRowSet.addRowSet</code> methods that takes both a
* <code>RowSet</code> object and a match column or an array of <code>RowSet</code>
* objects and an array of match columns.
* <P>
* To get access to the methods in the <code>Joinable</code> interface, a
* <code>RowSet</code> object implements at least one of the
* five standard <code>RowSet</code> interfaces and also implements the
* <code>Joinable</code> interface. In addition, most <code>RowSet</code>
* objects extend the <code>BaseRowSet</code> class. For example:
* <pre>
* class MyRowSetImpl extends BaseRowSet implements CachedRowSet, Joinable {
* :
* :
* }
* </pre>
*
* <h3>2.0 Usage Guidelines</h3>
* <P>
* The methods in the <code>Joinable</code> interface allow a <code>RowSet</code> object
* to set a match column, retrieve a match column, or unset a match column, which is
* the column upon which an SQL <code>JOIN</code> can be based.
* An instance of a class that implements these methods can be added to a
* <code>JoinRowSet</code> object to allow an SQL <code>JOIN</code> relationship to
* be established.
*
* <pre>
* CachedRowSet crs = new MyRowSetImpl();
* crs.populate((ResultSet)rs);
* (Joinable)crs.setMatchColumnIndex(1);
*
* JoinRowSet jrs = new JoinRowSetImpl();
* jrs.addRowSet(crs);
* </pre>
* In the previous example, <i>crs</i> is a <code>CachedRowSet</code> object that
* has implemented the <code>Joinable</code> interface. In the following example,
* <i>crs2</i> has not, so it must supply the match column as an argument to the
* <code>addRowSet</code> method. This example assumes that column 1 is the match
* column.
* <PRE>
* CachedRowSet crs2 = new MyRowSetImpl();
* crs2.populate((ResultSet)rs);
*
* JoinRowSet jrs2 = new JoinRowSetImpl();
* jrs2.addRowSet(crs2, 1);
* </PRE>
* <p>
* The <code>JoinRowSet</code> interface makes it possible to get data from one or
* more <code>RowSet</code> objects consolidated into one table without having to incur
* the expense of creating a connection to a database. It is therefore ideally suited
* for use by disconnected <code>RowSet</code> objects. Nevertheless, any
* <code>RowSet</code> object <b>may</b> implement this interface
* regardless of whether it is connected or disconnected. Note that a
* <code>JdbcRowSet</code> object, being always connected to its data source, can
* become part of an SQL <code>JOIN</code> directly without having to become part
* of a <code>JoinRowSet</code> object.
*
* <h3>3.0 Managing Multiple Match Columns</h3>
* The index array passed into the <code>setMatchColumn</code> methods indicates
* how many match columns are being set (the length of the array) in addition to
* which columns will be used for the match. For example:
* <pre>
* int[] i = {1, 2, 4, 7}; // indicates four match columns, with column
* // indexes 1, 2, 4, 7 participating in the JOIN.
* Joinable.setMatchColumn(i);
* </pre>
* Subsequent match columns may be added as follows to a different <code>Joinable</code>
* object (a <code>RowSet</code> object that has implemented the <code>Joinable</code>
* interface).
* <pre>
* int[] w = {3, 2, 5, 3};
* Joinable2.setMatchColumn(w);
* </pre>
* When an application adds two or more <code>RowSet</code> objects to a
* <code>JoinRowSet</code> object, the order of the indexes in the array is
* particularly important. Each index of
* the array maps directly to the corresponding index of the previously added
* <code>RowSet</code> object. If overlap or underlap occurs, the match column
* data is maintained in the event an additional <code>Joinable</code> RowSet is
* added and needs to relate to the match column data. Therefore, applications
* can set multiple match columns in any order, but
* this order has a direct effect on the outcome of the <code>SQL</code> JOIN.
* <p>
* This assertion applies in exactly the same manner when column names are used
* rather than column indexes to indicate match columns.
*
* @see JoinRowSet
* @author Jonathan Bruce
*/
public interface Joinable {
/**
* Sets the designated column as the match column for this <code>RowSet</code>
* object. A <code>JoinRowSet</code> object can now add this <code>RowSet</code>
* object based on the match column.
* <p>
* Sub-interfaces such as the <code>CachedRowSet</code>&trade;
* interface define the method <code>CachedRowSet.setKeyColumns</code>, which allows
* primary key semantics to be enforced on specific columns.
* Implementations of the <code>setMatchColumn(int columnIdx)</code> method
* should ensure that the constraints on the key columns are maintained when
* a <code>CachedRowSet</code> object sets a primary key column as a match column.
*
* @param columnIdx an <code>int</code> identifying the index of the column to be
* set as the match column
* @throws SQLException if an invalid column index is set
* @see #setMatchColumn(int[])
* @see #unsetMatchColumn(int)
*
*/
public void setMatchColumn(int columnIdx) throws SQLException;
/**
* Sets the designated columns as the match column for this <code>RowSet</code>
* object. A <code>JoinRowSet</code> object can now add this <code>RowSet</code>
* object based on the match column.
*
* @param columnIdxes an array of <code>int</code> identifying the indexes of the
* columns to be set as the match columns
* @throws SQLException if an invalid column index is set
* @see #setMatchColumn(int[])
* @see #unsetMatchColumn(int[])
*/
public void setMatchColumn(int[] columnIdxes) throws SQLException;
/**
* Sets the designated column as the match column for this <code>RowSet</code>
* object. A <code>JoinRowSet</code> object can now add this <code>RowSet</code>
* object based on the match column.
* <p>
* Subinterfaces such as the <code>CachedRowSet</code> interface define
* the method <code>CachedRowSet.setKeyColumns</code>, which allows
* primary key semantics to be enforced on specific columns.
* Implementations of the <code>setMatchColumn(String columnIdx)</code> method
* should ensure that the constraints on the key columns are maintained when
* a <code>CachedRowSet</code> object sets a primary key column as a match column.
*
* @param columnName a <code>String</code> object giving the name of the column
* to be set as the match column
* @throws SQLException if an invalid column name is set, the column name
* is a null, or the column name is an empty string
* @see #unsetMatchColumn
* @see #setMatchColumn(int[])
*/
public void setMatchColumn(String columnName) throws SQLException;
/**
* Sets the designated columns as the match column for this <code>RowSet</code>
* object. A <code>JoinRowSet</code> object can now add this <code>RowSet</code>
* object based on the match column.
*
* @param columnNames an array of <code>String</code> objects giving the names
* of the column to be set as the match columns
* @throws SQLException if an invalid column name is set, the column name
* is a null, or the column name is an empty string
* @see #unsetMatchColumn
* @see #setMatchColumn(int[])
*/
public void setMatchColumn(String[] columnNames) throws SQLException;
/**
* Retrieves the indexes of the match columns that were set for this
* <code>RowSet</code> object with the method
* <code>setMatchColumn(int[] columnIdxes)</code>.
*
* @return an <code>int</code> array identifying the indexes of the columns
* that were set as the match columns for this <code>RowSet</code> object
* @throws SQLException if no match column has been set
* @see #setMatchColumn
* @see #unsetMatchColumn
*/
public int[] getMatchColumnIndexes() throws SQLException;
/**
* Retrieves the names of the match columns that were set for this
* <code>RowSet</code> object with the method
* <code>setMatchColumn(String [] columnNames)</code>.
*
* @return an array of <code>String</code> objects giving the names of the columns
* set as the match columns for this <code>RowSet</code> object
* @throws SQLException if no match column has been set
* @see #setMatchColumn
* @see #unsetMatchColumn
*
*/
public String[] getMatchColumnNames() throws SQLException;
/**
* Unsets the designated column as the match column for this <code>RowSet</code>
* object.
* <P>
* <code>RowSet</code> objects that implement the <code>Joinable</code> interface
* must ensure that a key-like constraint continues to be enforced until the
* method <code>CachedRowSet.unsetKeyColumns</code> has been called on the
* designated column.
*
* @param columnIdx an <code>int</code> that identifies the index of the column
* that is to be unset as a match column
* @throws SQLException if an invalid column index is designated or if
* the designated column was not previously set as a match
* column
* @see #setMatchColumn
*/
public void unsetMatchColumn(int columnIdx) throws SQLException;
/**
* Unsets the designated columns as the match column for this <code>RowSet</code>
* object.
*
* @param columnIdxes an array of <code>int</code> that identifies the indexes
* of the columns that are to be unset as match columns
* @throws SQLException if an invalid column index is designated or if
* the designated column was not previously set as a match
* column
* @see #setMatchColumn
*/
public void unsetMatchColumn(int[] columnIdxes) throws SQLException;
/**
* Unsets the designated column as the match column for this <code>RowSet</code>
* object.
* <P>
* <code>RowSet</code> objects that implement the <code>Joinable</code> interface
* must ensure that a key-like constraint continues to be enforced until the
* method <code>CachedRowSet.unsetKeyColumns</code> has been called on the
* designated column.
*
* @param columnName a <code>String</code> object giving the name of the column
* that is to be unset as a match column
* @throws SQLException if an invalid column name is designated or
* the designated column was not previously set as a match
* column
* @see #setMatchColumn
*/
public void unsetMatchColumn(String columnName) throws SQLException;
/**
* Unsets the designated columns as the match columns for this <code>RowSet</code>
* object.
*
* @param columnName an array of <code>String</code> objects giving the names of
* the columns that are to be unset as the match columns
* @throws SQLException if an invalid column name is designated or the
* designated column was not previously set as a match column
* @see #setMatchColumn
*/
public void unsetMatchColumn(String[] columnName) throws SQLException;
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import javax.sql.*;
import java.sql.*;
/**
* The standard interface that provides the framework for all
* <code>FilteredRowSet</code> objects to describe their filters.
*
* <h3>1.0 Background</h3>
* The <code>Predicate</code> interface is a standard interface that
* applications can implement to define the filter they wish to apply to a
* a <code>FilteredRowSet</code> object. A <code>FilteredRowSet</code>
* object consumes implementations of this interface and enforces the
* constraints defined in the implementation of the method <code>evaluate</code>.
* A <code>FilteredRowSet</code> object enforces the filter constraints in a
* bi-directional manner: It outputs only rows that are within
* the constraints of the filter; and conversely, it inserts, modifies, or updates
* only rows that are within the constraints of the filter.
*
* <h3>2.0 Implementation Guidelines</h3>
* In order to supply a predicate for the <code>FilteredRowSet</code>.
* this interface must be implemented. At this time, the JDBC RowSet
* Implementations (JSR-114) does not specify any standard filters definitions.
* By specifying a standard means and mechanism for a range of filters to be
* defined and deployed with both the reference and vendor implementations
* of the <code>FilteredRowSet</code> interface, this allows for a flexible
* and application motivated implementations of <code>Predicate</code> to emerge.
* <p>
* A sample implementation would look something like this:
* <pre>{@code
* public class Range implements Predicate {
*
* private int[] lo;
* private int[] hi;
* private int[] idx;
*
* public Range(int[] lo, int[] hi, int[] idx) {
* this.lo = lo;
* this.hi = hi;
* this.idx = idx;
* }
*
* public boolean evaluate(RowSet rs) {
*
* // Check the present row determine if it lies
* // within the filtering criteria.
*
* for (int i = 0; i < idx.length; i++) {
* int value;
* try {
* value = (Integer) rs.getObject(idx[i]);
* } catch (SQLException ex) {
* Logger.getLogger(Range.class.getName()).log(Level.SEVERE, null, ex);
* return false;
* }
*
* if (value < lo[i] && value > hi[i]) {
* // outside of filter constraints
* return false;
* }
* }
* // Within filter constraints
* return true;
* }
* }
* }</pre>
* <P>
* The example above implements a simple range predicate. Note, that
* implementations should but are not required to provide <code>String</code>
* and integer index based constructors to provide for JDBC RowSet Implementation
* applications that use both column identification conventions.
*
* @author Jonathan Bruce, Amit Handa
*
*/
// <h3>3.0 FilteredRowSet Internals</h3>
// internalNext, Frist, Last. Discuss guidelines on how to approach this
// and cite examples in reference implementations.
public interface Predicate {
/**
* This method is typically called a <code>FilteredRowSet</code> object
* internal methods (not public) that control the <code>RowSet</code> object's
* cursor moving from row to the next. In addition, if this internal method
* moves the cursor onto a row that has been deleted, the internal method will
* continue to ove the cursor until a valid row is found.
* @param rs The {@code RowSet} to be evaluated
* @return <code>true</code> if there are more rows in the filter;
* <code>false</code> otherwise
*/
public boolean evaluate(RowSet rs);
/**
* This method is called by a <code>FilteredRowSet</code> object
* to check whether the value lies between the filtering criterion (or criteria
* if multiple constraints exist) set using the <code>setFilter()</code> method.
* <P>
* The <code>FilteredRowSet</code> object will use this method internally
* while inserting new rows to a <code>FilteredRowSet</code> instance.
*
* @param value An <code>Object</code> value which needs to be checked,
* whether it can be part of this <code>FilterRowSet</code> object.
* @param column a <code>int</code> object that must match the
* SQL index of a column in this <code>RowSet</code> object. This must
* have been passed to <code>Predicate</code> as one of the columns
* for filtering while initializing a <code>Predicate</code>
* @return <code>true</code> if row value lies within the filter;
* <code>false</code> otherwise
* @throws SQLException if the column is not part of filtering criteria
*/
public boolean evaluate(Object value, int column) throws SQLException;
/**
* This method is called by the <code>FilteredRowSet</code> object
* to check whether the value lies between the filtering criteria set
* using the setFilter method.
* <P>
* The <code>FilteredRowSet</code> object will use this method internally
* while inserting new rows to a <code>FilteredRowSet</code> instance.
*
* @param value An <code>Object</code> value which needs to be checked,
* whether it can be part of this <code>FilterRowSet</code>.
*
* @param columnName a <code>String</code> object that must match the
* SQL name of a column in this <code>RowSet</code>, ignoring case. This must
* have been passed to <code>Predicate</code> as one of the columns for filtering
* while initializing a <code>Predicate</code>
*
* @return <code>true</code> if value lies within the filter; <code>false</code> otherwise
*
* @throws SQLException if the column is not part of filtering criteria
*/
public boolean evaluate(Object value, String columnName) throws SQLException;
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import java.sql.SQLException;
/**
* An interface that defines the implementation of a factory that is used
* to obtain different types of {@code RowSet} implementations.
*
* @author Lance Andersen
* @since 1.7
*/
public interface RowSetFactory{
/**
* <p>Creates a new instance of a CachedRowSet.</p>
*
* @return A new instance of a CachedRowSet.
*
* @throws SQLException if a CachedRowSet cannot
* be created.
*
* @since 1.7
*/
public CachedRowSet createCachedRowSet() throws SQLException;
/**
* <p>Creates a new instance of a FilteredRowSet.</p>
*
* @return A new instance of a FilteredRowSet.
*
* @throws SQLException if a FilteredRowSet cannot
* be created.
*
* @since 1.7
*/
public FilteredRowSet createFilteredRowSet() throws SQLException;
/**
* <p>Creates a new instance of a JdbcRowSet.</p>
*
* @return A new instance of a JdbcRowSet.
*
* @throws SQLException if a JdbcRowSet cannot
* be created.
*
* @since 1.7
*/
public JdbcRowSet createJdbcRowSet() throws SQLException;
/**
* <p>Creates a new instance of a JoinRowSet.</p>
*
* @return A new instance of a JoinRowSet.
*
* @throws SQLException if a JoinRowSet cannot
* be created.
*
* @since 1.7
*/
public JoinRowSet createJoinRowSet() throws SQLException;
/**
* <p>Creates a new instance of a WebRowSet.</p>
*
* @return A new instance of a WebRowSet.
*
* @throws SQLException if a WebRowSet cannot
* be created.
*
* @since 1.7
*/
public WebRowSet createWebRowSet() throws SQLException;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,323 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.sql.SQLException;
import java.util.PropertyPermission;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import javax.sql.rowset.spi.SyncFactoryException;
import sun.reflect.misc.ReflectUtil;
/**
* A factory API that enables applications to obtain a
* {@code RowSetFactory} implementation that can be used to create different
* types of {@code RowSet} implementations.
* <p>
* Example:
* </p>
* <pre>
* RowSetFactory aFactory = RowSetProvider.newFactory();
* CachedRowSet crs = aFactory.createCachedRowSet();
* ...
* RowSetFactory rsf = RowSetProvider.newFactory("com.sun.rowset.RowSetFactoryImpl", null);
* WebRowSet wrs = rsf.createWebRowSet();
* </pre>
*<p>
* Tracing of this class may be enabled by setting the System property
* {@code javax.sql.rowset.RowSetFactory.debug} to any value but {@code false}.
* </p>
*
* @author Lance Andersen
* @since 1.7
*/
public class RowSetProvider {
private static final String ROWSET_DEBUG_PROPERTY = "javax.sql.rowset.RowSetProvider.debug";
private static final String ROWSET_FACTORY_IMPL = "com.sun.rowset.RowSetFactoryImpl";
private static final String ROWSET_FACTORY_NAME = "javax.sql.rowset.RowSetFactory";
/**
* Internal debug flag.
*/
private static boolean debug = true;
static {
// Check to see if the debug property is set
String val = getSystemProperty(ROWSET_DEBUG_PROPERTY);
// Allow simply setting the prop to turn on debug
debug = val != null && !"false".equals(val);
}
/**
* RowSetProvider constructor
*/
protected RowSetProvider () {
}
/**
* <p>Creates a new instance of a <code>RowSetFactory</code>
* implementation. This method uses the following
* look up order to determine
* the <code>RowSetFactory</code> implementation class to load:</p>
* <ul>
* <li>
* The System property {@code javax.sql.rowset.RowSetFactory}. For example:
* <ul>
* <li>
* -Djavax.sql.rowset.RowSetFactory=com.sun.rowset.RowSetFactoryImpl
* </li>
* </ul>
* <li>
* The {@link ServiceLoader} API. The {@code ServiceLoader} API will look
* for a class name in the file
* {@code META-INF/services/javax.sql.rowset.RowSetFactory}
* in jars available to the runtime. For example, to have the the RowSetFactory
* implementation {@code com.sun.rowset.RowSetFactoryImpl } loaded, the
* entry in {@code META-INF/services/javax.sql.rowset.RowSetFactory} would be:
* <ul>
* <li>
* {@code com.sun.rowset.RowSetFactoryImpl }
* </li>
* </ul>
* </li>
* <li>
* Platform default <code>RowSetFactory</code> instance.
* </li>
* </ul>
*
* <p>Once an application has obtained a reference to a {@code RowSetFactory},
* it can use the factory to obtain RowSet instances.</p>
*
* @return New instance of a <code>RowSetFactory</code>
*
* @throws SQLException if the default factory class cannot be loaded,
* instantiated. The cause will be set to actual Exception
*
* @see ServiceLoader
* @since 1.7
*/
public static RowSetFactory newFactory()
throws SQLException {
// Use the system property first
RowSetFactory factory = null;
String factoryClassName = null;
try {
trace("Checking for Rowset System Property...");
factoryClassName = getSystemProperty(ROWSET_FACTORY_NAME);
if (factoryClassName != null) {
trace("Found system property, value=" + factoryClassName);
factory = (RowSetFactory) ReflectUtil.newInstance(getFactoryClass(factoryClassName, null, true));
}
} catch (Exception e) {
throw new SQLException( "RowSetFactory: " + factoryClassName +
" could not be instantiated: ", e);
}
// Check to see if we found the RowSetFactory via a System property
if (factory == null) {
// If the RowSetFactory is not found via a System Property, now
// look it up via the ServiceLoader API and if not found, use the
// Java SE default.
factory = loadViaServiceLoader();
factory =
factory == null ? newFactory(ROWSET_FACTORY_IMPL, null) : factory;
}
return (factory);
}
/**
* <p>Creates a new instance of a <code>RowSetFactory</code> from the
* specified factory class name.
* This function is useful when there are multiple providers in the classpath.
* It gives more control to the application as it can specify which provider
* should be loaded.</p>
*
* <p>Once an application has obtained a reference to a <code>RowSetFactory</code>
* it can use the factory to obtain RowSet instances.</p>
*
* @param factoryClassName fully qualified factory class name that
* provides an implementation of <code>javax.sql.rowset.RowSetFactory</code>.
*
* @param cl <code>ClassLoader</code> used to load the factory
* class. If <code>null</code> current <code>Thread</code>'s context
* classLoader is used to load the factory class.
*
* @return New instance of a <code>RowSetFactory</code>
*
* @throws SQLException if <code>factoryClassName</code> is
* <code>null</code>, or the factory class cannot be loaded, instantiated.
*
* @see #newFactory()
*
* @since 1.7
*/
public static RowSetFactory newFactory(String factoryClassName, ClassLoader cl)
throws SQLException {
trace("***In newInstance()");
if(factoryClassName == null) {
throw new SQLException("Error: factoryClassName cannot be null");
}
try {
ReflectUtil.checkPackageAccess(factoryClassName);
} catch (java.security.AccessControlException e) {
throw new SQLException("Access Exception",e);
}
try {
Class<?> providerClass = getFactoryClass(factoryClassName, cl, false);
RowSetFactory instance = (RowSetFactory) providerClass.newInstance();
if (debug) {
trace("Created new instance of " + providerClass +
" using ClassLoader: " + cl);
}
return instance;
} catch (ClassNotFoundException x) {
throw new SQLException(
"Provider " + factoryClassName + " not found", x);
} catch (Exception x) {
throw new SQLException(
"Provider " + factoryClassName + " could not be instantiated: " + x,
x);
}
}
/*
* Returns the class loader to be used.
* @return The ClassLoader to use.
*
*/
static private ClassLoader getContextClassLoader() throws SecurityException {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
ClassLoader cl = null;
cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
}
return cl;
}
});
}
/**
* Attempt to load a class using the class loader supplied. If that fails
* and fall back is enabled, the current (i.e. bootstrap) class loader is
* tried.
*
* If the class loader supplied is <code>null</code>, first try using the
* context class loader followed by the current class loader.
* @return The class which was loaded
*/
static private Class<?> getFactoryClass(String factoryClassName, ClassLoader cl,
boolean doFallback) throws ClassNotFoundException {
try {
if (cl == null) {
cl = getContextClassLoader();
if (cl == null) {
throw new ClassNotFoundException();
} else {
return cl.loadClass(factoryClassName);
}
} else {
return cl.loadClass(factoryClassName);
}
} catch (ClassNotFoundException e) {
if (doFallback) {
// Use current class loader
return Class.forName(factoryClassName, true, RowSetFactory.class.getClassLoader());
} else {
throw e;
}
}
}
/**
* Use the ServiceLoader mechanism to load the default RowSetFactory
* @return default RowSetFactory Implementation
*/
static private RowSetFactory loadViaServiceLoader() throws SQLException {
RowSetFactory theFactory = null;
try {
trace("***in loadViaServiceLoader():");
for (RowSetFactory factory : ServiceLoader.load(javax.sql.rowset.RowSetFactory.class)) {
trace(" Loading done by the java.util.ServiceLoader :" + factory.getClass().getName());
theFactory = factory;
break;
}
} catch (ServiceConfigurationError e) {
throw new SQLException(
"RowSetFactory: Error locating RowSetFactory using Service "
+ "Loader API: " + e, e);
}
return theFactory;
}
/**
* Returns the requested System Property. If a {@code SecurityException}
* occurs, just return NULL
* @param propName - System property to retrieve
* @return The System property value or NULL if the property does not exist
* or a {@code SecurityException} occurs.
*/
static private String getSystemProperty(final String propName) {
String property = null;
try {
property = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty(propName);
}
}, null, new PropertyPermission(propName, "read"));
} catch (SecurityException se) {
trace("error getting " + propName + ": "+ se);
if (debug) {
se.printStackTrace();
}
}
return property;
}
/**
* Debug routine which will output tracing if the System Property
* -Djavax.sql.rowset.RowSetFactory.debug is set
* @param msg - The debug message to display
*/
private static void trace(String msg) {
if (debug) {
System.err.println("###RowSets: " + msg);
}
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import java.sql.SQLException;
/**
* An extension of <code>SQLException</code> that provides information
* about database warnings set on <code>RowSet</code> objects.
* Warnings are silently chained to the object whose method call
* caused it to be reported.
* This class complements the <code>SQLWarning</code> class.
* <P>
* Rowset warnings may be retrieved from <code>JdbcRowSet</code>,
* <code>CachedRowSet</code>&trade;,
* <code>WebRowSet</code>, <code>FilteredRowSet</code>, or <code>JoinRowSet</code>
* implementations. To retrieve the first warning reported on any
* <code>RowSet</code>
* implementation, use the method <code>getRowSetWarnings</code> defined
* in the <code>JdbcRowSet</code> interface or the <code>CachedRowSet</code>
* interface. To retrieve a warning chained to the first warning, use the
* <code>RowSetWarning</code> method
* <code>getNextWarning</code>. To retrieve subsequent warnings, call
* <code>getNextWarning</code> on each <code>RowSetWarning</code> object that is
* returned.
* <P>
* The inherited methods <code>getMessage</code>, <code>getSQLState</code>,
* and <code>getErrorCode</code> retrieve information contained in a
* <code>RowSetWarning</code> object.
*
* @since 1.5
*/
public class RowSetWarning extends SQLException {
/**
* Constructs a <code>RowSetWarning</code> object
* with the given value for the reason; SQLState defaults to null,
* and vendorCode defaults to 0.
*
* @param reason a <code>String</code> object giving a description
* of the warning; if the <code>String</code> is <code>null</code>,
* this constructor behaves like the default (zero parameter)
* <code>RowSetWarning</code> constructor
*/
public RowSetWarning(String reason) {
super(reason);
}
/**
* Constructs a default <code>RowSetWarning</code> object. The reason
* defaults to <code>null</code>, SQLState defaults to null and vendorCode
* defaults to 0.
*/
public RowSetWarning() {
super();
}
/**
* Constructs a <code>RowSetWarning</code> object initialized with the
* given values for the reason and SQLState. The vendor code defaults to 0.
*
* If the <code>reason</code> or <code>SQLState</code> parameters are <code>null</code>,
* this constructor behaves like the default (zero parameter)
* <code>RowSetWarning</code> constructor.
*
* @param reason a <code>String</code> giving a description of the
* warning;
* @param SQLState an XOPEN code identifying the warning; if a non standard
* XOPEN <i>SQLState</i> is supplied, no exception is thrown.
*/
public RowSetWarning(java.lang.String reason, java.lang.String SQLState) {
super(reason, SQLState);
}
/**
* Constructs a fully specified <code>RowSetWarning</code> object initialized
* with the given values for the reason, SQLState and vendorCode.
*
* If the <code>reason</code>, or the <code>SQLState</code>
* parameters are <code>null</code>, this constructor behaves like the default
* (zero parameter) <code>RowSetWarning</code> constructor.
*
* @param reason a <code>String</code> giving a description of the
* warning;
* @param SQLState an XOPEN code identifying the warning; if a non standard
* XOPEN <i>SQLState</i> is supplied, no exception is thrown.
* @param vendorCode a database vendor-specific warning code
*/
public RowSetWarning(java.lang.String reason, java.lang.String SQLState, int vendorCode) {
super(reason, SQLState, vendorCode);
}
/**
* Retrieves the warning chained to this <code>RowSetWarning</code>
* object.
*
* @return the <code>RowSetWarning</code> object chained to this one; if no
* <code>RowSetWarning</code> object is chained to this one,
* <code>null</code> is returned (default value)
* @see #setNextWarning
*/
public RowSetWarning getNextWarning() {
SQLException warning = getNextException();
if ( warning == null || warning instanceof RowSetWarning) {
return (RowSetWarning)warning;
} else {
// The chained value isn't a RowSetWarning.
// This is a programming error by whoever added it to
// the RowSetWarning chain. We throw a Java "Error".
throw new Error("RowSetWarning chain holds value that is not a RowSetWarning: ");
}
}
/**
* Sets <i>warning</i> as the next warning, that is, the warning chained
* to this <code>RowSetWarning</code> object.
*
* @param warning the <code>RowSetWarning</code> object to be set as the
* next warning; if the <code>RowSetWarning</code> is null, this
* represents the finish point in the warning chain
* @see #getNextWarning
*/
public void setNextWarning(RowSetWarning warning) {
setNextException(warning);
}
static final long serialVersionUID = 6678332766434564774L;
}

View File

@@ -0,0 +1,505 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import java.io.*;
import java.math.*;
import org.xml.sax.*;
/**
* The standard interface that all implementations of a {@code WebRowSet}
* must implement.
*
* <h3>1.0 Overview</h3>
* The {@code WebRowSetImpl} provides the standard
* reference implementation, which may be extended if required.
* <P>
* The standard WebRowSet XML Schema definition is available at the following
* URI:
* <ul>
* <li>
* <a href="http://java.sun.com/xml/ns/jdbc/webrowset.xsd">http://java.sun.com/xml/ns/jdbc/webrowset.xsd</a>
* </li>
* </ul>
* It describes the standard XML document format required when describing a
* {@code RowSet} object in XML and must be used be all standard implementations
* of the {@code WebRowSet} interface to ensure interoperability. In addition,
* the {@code WebRowSet} schema uses specific SQL/XML Schema annotations,
* thus ensuring greater cross
* platform inter-operability. This is an effort currently under way at the ISO
* organization. The SQL/XML definition is available at the following URI:
* <ul>
* <li>
* <a href="http://standards.iso.org/iso/9075/2002/12/sqlxml">http://standards.iso.org/iso/9075/2002/12/sqlxml</a>
* </li>
* </ul>
* The schema definition describes the internal data of a {@code RowSet} object
* in three distinct areas:
* <UL>
* <li>properties - These properties describe the standard synchronization
* provider properties in addition to the more general {@code RowSet} properties.
* </li>
* <li>metadata - This describes the metadata associated with the tabular structure governed by a
* {@code WebRowSet} object. The metadata described is closely aligned with the
* metadata accessible in the underlying {@code java.sql.ResultSet} interface.
* </li>
* <li>data - This describes the original data (the state of data since the
* last population
* or last synchronization of the {@code WebRowSet} object) and the current
* data. By keeping track of the delta between the original data and the current data,
* a {@code WebRowSet} maintains the ability to synchronize changes
* in its data back to the originating data source.
* </li>
* </ul>
*
* <h3>2.0 WebRowSet States</h3>
* The following sections demonstrates how a {@code WebRowSet} implementation
* should use the XML Schema to describe update, insert, and delete operations
* and to describe the state of a {@code WebRowSet} object in XML.
*
* <h4>2.1 State 1 - Outputting a {@code WebRowSet} Object to XML</h4>
* In this example, a {@code WebRowSet} object is created and populated with a simple 2 column,
* 5 row table from a data source. Having the 5 rows in a {@code WebRowSet} object
* makes it possible to describe them in XML. The
* metadata describing the various standard JavaBeans properties as defined
* in the RowSet interface plus the standard properties defined in
* the {@code CachedRowSet}&trade; interface
* provide key details that describe WebRowSet
* properties. Outputting the WebRowSet object to XML using the standard
* {@code writeXml} methods describes the internal properties as follows:
* <PRE>
* {@code
* <properties>
* <command>select co1, col2 from test_table</command>
* <concurrency>1</concurrency>
* <datasource/>
* <escape-processing>true</escape-processing>
* <fetch-direction>0</fetch-direction>
* <fetch-size>0</fetch-size>
* <isolation-level>1</isolation-level>
* <key-columns/>
* <map/>
* <max-field-size>0</max-field-size>
* <max-rows>0</max-rows>
* <query-timeout>0</query-timeout>
* <read-only>false</read-only>
* <rowset-type>TRANSACTION_READ_UNCOMMITED</rowset-type>
* <show-deleted>false</show-deleted>
* <table-name/>
* <url>jdbc:thin:oracle</url>
* <sync-provider>
* <sync-provider-name>.com.rowset.provider.RIOptimisticProvider</sync-provider-name>
* <sync-provider-vendor>Oracle Corporation</sync-provider-vendor>
* <sync-provider-version>1.0</sync-provider-name>
* <sync-provider-grade>LOW</sync-provider-grade>
* <data-source-lock>NONE</data-source-lock>
* </sync-provider>
* </properties>
* } </PRE>
* The meta-data describing the make up of the WebRowSet is described
* in XML as detailed below. Note both columns are described between the
* {@code column-definition} tags.
* <PRE>
* {@code
* <metadata>
* <column-count>2</column-count>
* <column-definition>
* <column-index>1</column-index>
* <auto-increment>false</auto-increment>
* <case-sensitive>true</case-sensitive>
* <currency>false</currency>
* <nullable>1</nullable>
* <signed>false</signed>
* <searchable>true</searchable>
* <column-display-size>10</column-display-size>
* <column-label>COL1</column-label>
* <column-name>COL1</column-name>
* <schema-name/>
* <column-precision>10</column-precision>
* <column-scale>0</column-scale>
* <table-name/>
* <catalog-name/>
* <column-type>1</column-type>
* <column-type-name>CHAR</column-type-name>
* </column-definition>
* <column-definition>
* <column-index>2</column-index>
* <auto-increment>false</auto-increment>
* <case-sensitive>false</case-sensitive>
* <currency>false</currency>
* <nullable>1</nullable>
* <signed>true</signed>
* <searchable>true</searchable>
* <column-display-size>39</column-display-size>
* <column-label>COL2</column-label>
* <column-name>COL2</column-name>
* <schema-name/>
* <column-precision>38</column-precision>
* <column-scale>0</column-scale>
* <table-name/>
* <catalog-name/>
* <column-type>3</column-type>
* <column-type-name>NUMBER</column-type-name>
* </column-definition>
* </metadata>
* }</PRE>
* Having detailed how the properties and metadata are described, the following details
* how the contents of a {@code WebRowSet} object is described in XML. Note, that
* this describes a {@code WebRowSet} object that has not undergone any
* modifications since its instantiation.
* A {@code currentRow} tag is mapped to each row of the table structure that the
* {@code WebRowSet} object provides. A {@code columnValue} tag may contain
* either the {@code stringData} or {@code binaryData} tag, according to
* the SQL type that
* the XML value is mapping back to. The {@code binaryData} tag contains data in the
* Base64 encoding and is typically used for {@code BLOB} and {@code CLOB} type data.
* <PRE>
* {@code
* <data>
* <currentRow>
* <columnValue>
* firstrow
* </columnValue>
* <columnValue>
* 1
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* secondrow
* </columnValue>
* <columnValue>
* 2
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* thirdrow
* </columnValue>
* <columnValue>
* 3
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* fourthrow
* </columnValue>
* <columnValue>
* 4
* </columnValue>
* </currentRow>
* </data>
* }</PRE>
* <h4>2.2 State 2 - Deleting a Row</h4>
* Deleting a row in a {@code WebRowSet} object involves simply moving to the row
* to be deleted and then calling the method {@code deleteRow}, as in any other
* {@code RowSet} object. The following
* two lines of code, in which <i>wrs</i> is a {@code WebRowSet} object, delete
* the third row.
* <PRE>
* wrs.absolute(3);
* wrs.deleteRow();
* </PRE>
* The XML description shows the third row is marked as a {@code deleteRow},
* which eliminates the third row in the {@code WebRowSet} object.
* <PRE>
* {@code
* <data>
* <currentRow>
* <columnValue>
* firstrow
* </columnValue>
* <columnValue>
* 1
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* secondrow
* </columnValue>
* <columnValue>
* 2
* </columnValue>
* </currentRow>
* <deleteRow>
* <columnValue>
* thirdrow
* </columnValue>
* <columnValue>
* 3
* </columnValue>
* </deleteRow>
* <currentRow>
* <columnValue>
* fourthrow
* </columnValue>
* <columnValue>
* 4
* </columnValue>
* </currentRow>
* </data>
*} </PRE>
* <h4>2.3 State 3 - Inserting a Row</h4>
* A {@code WebRowSet} object can insert a new row by moving to the insert row,
* calling the appropriate updater methods for each column in the row, and then
* calling the method {@code insertRow}.
* <PRE>
* {@code
* wrs.moveToInsertRow();
* wrs.updateString(1, "fifththrow");
* wrs.updateString(2, "5");
* wrs.insertRow();
* }</PRE>
* The following code fragment changes the second column value in the row just inserted.
* Note that this code applies when new rows are inserted right after the current row,
* which is why the method {@code next} moves the cursor to the correct row.
* Calling the method {@code acceptChanges} writes the change to the data source.
*
* <PRE>
* {@code wrs.moveToCurrentRow();
* wrs.next();
* wrs.updateString(2, "V");
* wrs.acceptChanges();
* }</PRE>
* Describing this in XML demonstrates where the Java code inserts a new row and then
* performs an update on the newly inserted row on an individual field.
* <PRE>
* {@code
* <data>
* <currentRow>
* <columnValue>
* firstrow
* </columnValue>
* <columnValue>
* 1
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* secondrow
* </columnValue>
* <columnValue>
* 2
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* newthirdrow
* </columnValue>
* <columnValue>
* III
* </columnValue>
* </currentRow>
* <insertRow>
* <columnValue>
* fifthrow
* </columnValue>
* <columnValue>
* 5
* </columnValue>
* <updateValue>
* V
* </updateValue>
* </insertRow>
* <currentRow>
* <columnValue>
* fourthrow
* </columnValue>
* <columnValue>
* 4
* </columnValue>
* </currentRow>
* </date>
*} </PRE>
* <h4>2.4 State 4 - Modifying a Row</h4>
* Modifying a row produces specific XML that records both the new value and the
* value that was replaced. The value that was replaced becomes the original value,
* and the new value becomes the current value. The following
* code moves the cursor to a specific row, performs some modifications, and updates
* the row when complete.
* <PRE>
*{@code
* wrs.absolute(5);
* wrs.updateString(1, "new4thRow");
* wrs.updateString(2, "IV");
* wrs.updateRow();
* }</PRE>
* In XML, this is described by the {@code modifyRow} tag. Both the original and new
* values are contained within the tag for original row tracking purposes.
* <PRE>
* {@code
* <data>
* <currentRow>
* <columnValue>
* firstrow
* </columnValue>
* <columnValue>
* 1
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* secondrow
* </columnValue>
* <columnValue>
* 2
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* newthirdrow
* </columnValue>
* <columnValue>
* III
* </columnValue>
* </currentRow>
* <currentRow>
* <columnValue>
* fifthrow
* </columnValue>
* <columnValue>
* 5
* </columnValue>
* </currentRow>
* <modifyRow>
* <columnValue>
* fourthrow
* </columnValue>
* <updateValue>
* new4thRow
* </updateValue>
* <columnValue>
* 4
* </columnValue>
* <updateValue>
* IV
* </updateValue>
* </modifyRow>
* </data>
* }</PRE>
*
* @see javax.sql.rowset.JdbcRowSet
* @see javax.sql.rowset.CachedRowSet
* @see javax.sql.rowset.FilteredRowSet
* @see javax.sql.rowset.JoinRowSet
*/
public interface WebRowSet extends CachedRowSet {
/**
* Reads a {@code WebRowSet} object in its XML format from the given
* {@code Reader} object.
*
* @param reader the {@code java.io.Reader} stream from which this
* {@code WebRowSet} object will be populated
* @throws SQLException if a database access error occurs
*/
public void readXml(java.io.Reader reader) throws SQLException;
/**
* Reads a stream based XML input to populate this {@code WebRowSet}
* object.
*
* @param iStream the {@code java.io.InputStream} from which this
* {@code WebRowSet} object will be populated
* @throws SQLException if a data source access error occurs
* @throws IOException if an IO exception occurs
*/
public void readXml(java.io.InputStream iStream) throws SQLException, IOException;
/**
* Populates this {@code WebRowSet} object with
* the contents of the given {@code ResultSet} object and writes its
* data, properties, and metadata
* to the given {@code Writer} object in XML format.
* <p>
* NOTE: The {@code WebRowSet} cursor may be moved to write out the
* contents to the XML data source. If implemented in this way, the cursor <b>must</b>
* be returned to its position just prior to the {@code writeXml()} call.
*
* @param rs the {@code ResultSet} object with which to populate this
* {@code WebRowSet} object
* @param writer the {@code java.io.Writer} object to write to.
* @throws SQLException if an error occurs writing out the rowset
* contents in XML format
*/
public void writeXml(ResultSet rs, java.io.Writer writer) throws SQLException;
/**
* Populates this {@code WebRowSet} object with
* the contents of the given {@code ResultSet} object and writes its
* data, properties, and metadata
* to the given {@code OutputStream} object in XML format.
* <p>
* NOTE: The {@code WebRowSet} cursor may be moved to write out the
* contents to the XML data source. If implemented in this way, the cursor <b>must</b>
* be returned to its position just prior to the {@code writeXml()} call.
*
* @param rs the {@code ResultSet} object with which to populate this
* {@code WebRowSet} object
* @param oStream the {@code java.io.OutputStream} to write to
* @throws SQLException if a data source access error occurs
* @throws IOException if a IO exception occurs
*/
public void writeXml(ResultSet rs, java.io.OutputStream oStream) throws SQLException, IOException;
/**
* Writes the data, properties, and metadata for this {@code WebRowSet} object
* to the given {@code Writer} object in XML format.
*
* @param writer the {@code java.io.Writer} stream to write to
* @throws SQLException if an error occurs writing out the rowset
* contents to XML
*/
public void writeXml(java.io.Writer writer) throws SQLException;
/**
* Writes the data, properties, and metadata for this {@code WebRowSet} object
* to the given {@code OutputStream} object in XML format.
*
* @param oStream the {@code java.io.OutputStream} stream to write to
* @throws SQLException if a data source access error occurs
* @throws IOException if a IO exception occurs
*/
public void writeXml(java.io.OutputStream oStream) throws SQLException, IOException;
/**
* The public identifier for the XML Schema definition that defines the XML
* tags and their valid values for a {@code WebRowSet} implementation.
*/
public static String PUBLIC_XML_SCHEMA =
"--//Oracle Corporation//XSD Schema//EN";
/**
* The URL for the XML Schema definition file that defines the XML tags and
* their valid values for a {@code WebRowSet} implementation.
*/
public static String SCHEMA_SYSTEM_ID = "http://java.sun.com/xml/ns/jdbc/webrowset.xsd";
}

View File

@@ -0,0 +1,668 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.sql.*;
import java.util.Arrays;
import java.util.Map;
import sun.reflect.misc.ReflectUtil;
/**
* An input stream used for custom mapping user-defined types (UDTs).
* An <code>SQLInputImpl</code> object is an input stream that contains a
* stream of values that are the attributes of a UDT.
* <p>
* This class is used by the driver behind the scenes when the method
* <code>getObject</code> is called on an SQL structured or distinct type
* that has a custom mapping; a programmer never invokes
* <code>SQLInputImpl</code> methods directly. They are provided here as a
* convenience for those who write <code>RowSet</code> implementations.
* <P>
* The <code>SQLInputImpl</code> class provides a set of
* reader methods analogous to the <code>ResultSet</code> getter
* methods. These methods make it possible to read the values in an
* <code>SQLInputImpl</code> object.
* <P>
* The method <code>wasNull</code> is used to determine whether the
* the last value read was SQL <code>NULL</code>.
* <P>When the method <code>getObject</code> is called with an
* object of a class implementing the interface <code>SQLData</code>,
* the JDBC driver calls the method <code>SQLData.getSQLType</code>
* to determine the SQL type of the UDT being custom mapped. The driver
* creates an instance of <code>SQLInputImpl</code>, populating it with the
* attributes of the UDT. The driver then passes the input
* stream to the method <code>SQLData.readSQL</code>, which in turn
* calls the <code>SQLInputImpl</code> reader methods
* to read the attributes from the input stream.
* @since 1.5
* @see java.sql.SQLData
*/
public class SQLInputImpl implements SQLInput {
/**
* <code>true</code> if the last value returned was <code>SQL NULL</code>;
* <code>false</code> otherwise.
*/
private boolean lastValueWasNull;
/**
* The current index into the array of SQL structured type attributes
* that will be read from this <code>SQLInputImpl</code> object and
* mapped to the fields of a class in the Java programming language.
*/
private int idx;
/**
* The array of attributes to be read from this stream. The order
* of the attributes is the same as the order in which they were
* listed in the SQL definition of the UDT.
*/
private Object attrib[];
/**
* The type map to use when the method <code>readObject</code>
* is invoked. This is a <code>java.util.Map</code> object in which
* there may be zero or more entries. Each entry consists of the
* fully qualified name of a UDT (the value to be mapped) and the
* <code>Class</code> object for a class that implements
* <code>SQLData</code> (the Java class that defines how the UDT
* will be mapped).
*/
private Map<String,Class<?>> map;
/**
* Creates an <code>SQLInputImpl</code> object initialized with the
* given array of attributes and the given type map. If any of the
* attributes is a UDT whose name is in an entry in the type map,
* the attribute will be mapped according to the corresponding
* <code>SQLData</code> implementation.
*
* @param attributes an array of <code>Object</code> instances in which
* each element is an attribute of a UDT. The order of the
* attributes in the array is the same order in which
* the attributes were defined in the UDT definition.
* @param map a <code>java.util.Map</code> object containing zero or more
* entries, with each entry consisting of 1) a <code>String</code>
* giving the fully
* qualified name of the UDT and 2) the <code>Class</code> object
* for the <code>SQLData</code> implementation that defines how
* the UDT is to be mapped
* @throws SQLException if the <code>attributes</code> or the <code>map</code>
* is a <code>null</code> value
*/
public SQLInputImpl(Object[] attributes, Map<String,Class<?>> map)
throws SQLException
{
if ((attributes == null) || (map == null)) {
throw new SQLException("Cannot instantiate a SQLInputImpl " +
"object with null parameters");
}
// assign our local reference to the attribute stream
attrib = Arrays.copyOf(attributes, attributes.length);
// init the index point before the head of the stream
idx = -1;
// set the map
this.map = map;
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as an <code>Object</code> in the Java programming language.
*
* @return the next value in the input stream
* as an <code>Object</code> in the Java programming language
* @throws SQLException if the read position is located at an invalid
* position or if there are no further values in the stream
*/
private Object getNextAttribute() throws SQLException {
if (++idx >= attrib.length) {
throw new SQLException("SQLInputImpl exception: Invalid read " +
"position");
} else {
lastValueWasNull = attrib[idx] == null;
return attrib[idx];
}
}
//================================================================
// Methods for reading attributes from the stream of SQL data.
// These methods correspond to the column-accessor methods of
// java.sql.ResultSet.
//================================================================
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object as
* a <code>String</code> in the Java programming language.
* <p>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code>
* implementation.
* <p>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no further values in the stream.
*/
public String readString() throws SQLException {
return (String)getNextAttribute();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object as
* a <code>boolean</code> in the Java programming language.
* <p>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code>
* implementation.
* <p>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no further values in the stream.
*/
public boolean readBoolean() throws SQLException {
Boolean attrib = (Boolean)getNextAttribute();
return (attrib == null) ? false : attrib.booleanValue();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object as
* a <code>byte</code> in the Java programming language.
* <p>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code>
* implementation.
* <p>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no further values in the stream
*/
public byte readByte() throws SQLException {
Byte attrib = (Byte)getNextAttribute();
return (attrib == null) ? 0 : attrib.byteValue();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as a <code>short</code> in the Java programming language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code> implementation.
* <P>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no more values in the stream
*/
public short readShort() throws SQLException {
Short attrib = (Short)getNextAttribute();
return (attrib == null) ? 0 : attrib.shortValue();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as an <code>int</code> in the Java programming language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code> implementation.
* <P>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no more values in the stream
*/
public int readInt() throws SQLException {
Integer attrib = (Integer)getNextAttribute();
return (attrib == null) ? 0 : attrib.intValue();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as a <code>long</code> in the Java programming language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code> implementation.
* <P>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no more values in the stream
*/
public long readLong() throws SQLException {
Long attrib = (Long)getNextAttribute();
return (attrib == null) ? 0 : attrib.longValue();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as a <code>float</code> in the Java programming language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code> implementation.
* <P>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no more values in the stream
*/
public float readFloat() throws SQLException {
Float attrib = (Float)getNextAttribute();
return (attrib == null) ? 0 : attrib.floatValue();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as a <code>double</code> in the Java programming language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code> implementation.
* <P>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no more values in the stream
*/
public double readDouble() throws SQLException {
Double attrib = (Double)getNextAttribute();
return (attrib == null) ? 0 : attrib.doubleValue();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as a <code>java.math.BigDecimal</code>.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code> implementation.
* <P>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no more values in the stream
*/
public java.math.BigDecimal readBigDecimal() throws SQLException {
return (java.math.BigDecimal)getNextAttribute();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as an array of bytes.
* <p>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code> implementation.
* <P>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no more values in the stream
*/
public byte[] readBytes() throws SQLException {
return (byte[])getNextAttribute();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> as
* a <code>java.sql.Date</code> object.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type; this responsibility is delegated
* to the UDT mapping as defined by a <code>SQLData</code> implementation.
* <P>
* @return the next attribute in this <code>SQLInputImpl</code> object;
* if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position or if there are no more values in the stream
*/
public java.sql.Date readDate() throws SQLException {
return (java.sql.Date)getNextAttribute();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object as
* a <code>java.sql.Time</code> object.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type as this responsibility is delegated
* to the UDT mapping as implemented by a <code>SQLData</code>
* implementation.
*
* @return the attribute; if the value is <code>SQL NULL</code>, return
* <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public java.sql.Time readTime() throws SQLException {
return (java.sql.Time)getNextAttribute();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object as
* a <code>java.sql.Timestamp</code> object.
*
* @return the attribute; if the value is <code>SQL NULL</code>, return
* <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public java.sql.Timestamp readTimestamp() throws SQLException {
return (java.sql.Timestamp)getNextAttribute();
}
/**
* Retrieves the next attribute in this <code>SQLInputImpl</code> object
* as a stream of Unicode characters.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type as this responsibility is delegated
* to the UDT mapping as implemented by a <code>SQLData</code>
* implementation.
*
* @return the attribute; if the value is <code>SQL NULL</code>, return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public java.io.Reader readCharacterStream() throws SQLException {
return (java.io.Reader)getNextAttribute();
}
/**
* Returns the next attribute in this <code>SQLInputImpl</code> object
* as a stream of ASCII characters.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type as this responsibility is delegated
* to the UDT mapping as implemented by a <code>SQLData</code>
* implementation.
*
* @return the attribute; if the value is <code>SQL NULL</code>,
* return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public java.io.InputStream readAsciiStream() throws SQLException {
return (java.io.InputStream)getNextAttribute();
}
/**
* Returns the next attribute in this <code>SQLInputImpl</code> object
* as a stream of uninterpreted bytes.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type as this responsibility is delegated
* to the UDT mapping as implemented by a <code>SQLData</code>
* implementation.
*
* @return the attribute; if the value is <code>SQL NULL</code>, return
* <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public java.io.InputStream readBinaryStream() throws SQLException {
return (java.io.InputStream)getNextAttribute();
}
//================================================================
// Methods for reading items of SQL user-defined types from the stream.
//================================================================
/**
* Retrieves the value at the head of this <code>SQLInputImpl</code>
* object as an <code>Object</code> in the Java programming language. The
* actual type of the object returned is determined by the default
* mapping of SQL types to types in the Java programming language unless
* there is a custom mapping, in which case the type of the object
* returned is determined by this stream's type map.
* <P>
* The JDBC technology-enabled driver registers a type map with the stream
* before passing the stream to the application.
* <P>
* When the datum at the head of the stream is an SQL <code>NULL</code>,
* this method returns <code>null</code>. If the datum is an SQL
* structured or distinct type with a custom mapping, this method
* determines the SQL type of the datum at the head of the stream,
* constructs an object of the appropriate class, and calls the method
* <code>SQLData.readSQL</code> on that object. The <code>readSQL</code>
* method then calls the appropriate <code>SQLInputImpl.readXXX</code>
* methods to retrieve the attribute values from the stream.
*
* @return the value at the head of the stream as an <code>Object</code>
* in the Java programming language; <code>null</code> if
* the value is SQL <code>NULL</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public Object readObject() throws SQLException {
Object attrib = getNextAttribute();
if (attrib instanceof Struct) {
Struct s = (Struct)attrib;
// look up the class in the map
Class<?> c = map.get(s.getSQLTypeName());
if (c != null) {
// create new instance of the class
SQLData obj = null;
try {
obj = (SQLData)ReflectUtil.newInstance(c);
} catch (Exception ex) {
throw new SQLException("Unable to Instantiate: ", ex);
}
// get the attributes from the struct
Object attribs[] = s.getAttributes(map);
// create the SQLInput "stream"
SQLInputImpl sqlInput = new SQLInputImpl(attribs, map);
// read the values...
obj.readSQL(sqlInput, s.getSQLTypeName());
return obj;
}
}
return attrib;
}
/**
* Retrieves the value at the head of this <code>SQLInputImpl</code> object
* as a <code>Ref</code> object in the Java programming language.
*
* @return a <code>Ref</code> object representing the SQL
* <code>REF</code> value at the head of the stream; if the value
* is <code>SQL NULL</code> return <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public Ref readRef() throws SQLException {
return (Ref)getNextAttribute();
}
/**
* Retrieves the <code>BLOB</code> value at the head of this
* <code>SQLInputImpl</code> object as a <code>Blob</code> object
* in the Java programming language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type as this responsibility is delegated
* to the UDT mapping as implemented by a <code>SQLData</code>
* implementation.
*
* @return a <code>Blob</code> object representing the SQL
* <code>BLOB</code> value at the head of this stream;
* if the value is <code>SQL NULL</code>, return
* <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public Blob readBlob() throws SQLException {
return (Blob)getNextAttribute();
}
/**
* Retrieves the <code>CLOB</code> value at the head of this
* <code>SQLInputImpl</code> object as a <code>Clob</code> object
* in the Java programming language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type as this responsibility is delegated
* to the UDT mapping as implemented by a <code>SQLData</code>
* implementation.
*
* @return a <code>Clob</code> object representing the SQL
* <code>CLOB</code> value at the head of the stream;
* if the value is <code>SQL NULL</code>, return
* <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public Clob readClob() throws SQLException {
return (Clob)getNextAttribute();
}
/**
* Reads an SQL <code>ARRAY</code> value from the stream and
* returns it as an <code>Array</code> object in the Java programming
* language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type as this responsibility is delegated
* to the UDT mapping as implemented by a <code>SQLData</code>
* implementation.
*
* @return an <code>Array</code> object representing the SQL
* <code>ARRAY</code> value at the head of the stream; *
* if the value is <code>SQL NULL</code>, return
* <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public Array readArray() throws SQLException {
return (Array)getNextAttribute();
}
/**
* Ascertains whether the last value read from this
* <code>SQLInputImpl</code> object was <code>null</code>.
*
* @return <code>true</code> if the SQL value read most recently was
* <code>null</code>; otherwise, <code>false</code>; by default it
* will return false
* @throws SQLException if an error occurs determining the last value
* read was a <code>null</code> value or not;
*/
public boolean wasNull() throws SQLException {
return lastValueWasNull;
}
/**
* Reads an SQL <code>DATALINK</code> value from the stream and
* returns it as an <code>URL</code> object in the Java programming
* language.
* <P>
* This method does not perform type-safe checking to determine if the
* returned type is the expected type as this responsibility is delegated
* to the UDT mapping as implemented by a <code>SQLData</code>
* implementation.
*
* @return an <code>URL</code> object representing the SQL
* <code>DATALINK</code> value at the head of the stream; *
* if the value is <code>SQL NULL</code>, return
* <code>null</code>
* @throws SQLException if the read position is located at an invalid
* position; or if there are no further values in the stream.
*/
public java.net.URL readURL() throws SQLException {
return (java.net.URL)getNextAttribute();
}
//---------------------------- JDBC 4.0 -------------------------
/**
* Reads an SQL <code>NCLOB</code> value from the stream and returns it as a
* <code>Clob</code> object in the Java programming language.
*
* @return a <code>NClob</code> object representing data of the SQL <code>NCLOB</code> value
* at the head of the stream; <code>null</code> if the value read is
* SQL <code>NULL</code>
* @exception SQLException if a database access error occurs
* @since 1.6
*/
public NClob readNClob() throws SQLException {
return (NClob)getNextAttribute();
}
/**
* Reads the next attribute in the stream and returns it as a <code>String</code>
* in the Java programming language. It is intended for use when
* accessing <code>NCHAR</code>,<code>NVARCHAR</code>
* and <code>LONGNVARCHAR</code> columns.
*
* @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
* @exception SQLException if a database access error occurs
* @since 1.6
*/
public String readNString() throws SQLException {
return (String)getNextAttribute();
}
/**
* Reads an SQL <code>XML</code> value from the stream and returns it as a
* <code>SQLXML</code> object in the Java programming language.
*
* @return a <code>SQLXML</code> object representing data of the SQL <code>XML</code> value
* at the head of the stream; <code>null</code> if the value read is
* SQL <code>NULL</code>
* @exception SQLException if a database access error occurs
* @since 1.6
*/
public SQLXML readSQLXML() throws SQLException {
return (SQLXML)getNextAttribute();
}
/**
* Reads an SQL <code>ROWID</code> value from the stream and returns it as a
* <code>RowId</code> object in the Java programming language.
*
* @return a <code>RowId</code> object representing data of the SQL <code>ROWID</code> value
* at the head of the stream; <code>null</code> if the value read is
* SQL <code>NULL</code>
* @exception SQLException if a database access error occurs
* @since 1.6
*/
public RowId readRowId() throws SQLException {
return (RowId)getNextAttribute();
}
}

View File

@@ -0,0 +1,644 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.*;
import java.util.Map;
import java.util.Vector;
/**
* The output stream for writing the attributes of a
* custom-mapped user-defined type (UDT) back to the database.
* The driver uses this interface internally, and its
* methods are never directly invoked by an application programmer.
* <p>
* When an application calls the
* method <code>PreparedStatement.setObject</code>, the driver
* checks to see whether the value to be written is a UDT with
* a custom mapping. If it is, there will be an entry in a
* type map containing the <code>Class</code> object for the
* class that implements <code>SQLData</code> for this UDT.
* If the value to be written is an instance of <code>SQLData</code>,
* the driver will create an instance of <code>SQLOutputImpl</code>
* and pass it to the method <code>SQLData.writeSQL</code>.
* The method <code>writeSQL</code> in turn calls the
* appropriate <code>SQLOutputImpl.writeXXX</code> methods
* to write data from the <code>SQLData</code> object to
* the <code>SQLOutputImpl</code> output stream as the
* representation of an SQL user-defined type.
*/
public class SQLOutputImpl implements SQLOutput {
/**
* A reference to an existing vector that
* contains the attributes of a <code>Struct</code> object.
*/
@SuppressWarnings("rawtypes")
private Vector attribs;
/**
* The type map the driver supplies to a newly created
* <code>SQLOutputImpl</code> object. This type map
* indicates the <code>SQLData</code> class whose
* <code>writeSQL</code> method will be called. This
* method will in turn call the appropriate
* <code>SQLOutputImpl</code> writer methods.
*/
@SuppressWarnings("rawtypes")
private Map map;
/**
* Creates a new <code>SQLOutputImpl</code> object
* initialized with the given vector of attributes and
* type map. The driver will use the type map to determine
* which <code>SQLData.writeSQL</code> method to invoke.
* This method will then call the appropriate
* <code>SQLOutputImpl</code> writer methods in order and
* thereby write the attributes to the new output stream.
*
* @param attributes a <code>Vector</code> object containing the attributes of
* the UDT to be mapped to one or more objects in the Java
* programming language
*
* @param map a <code>java.util.Map</code> object containing zero or
* more entries, with each entry consisting of 1) a <code>String</code>
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @throws SQLException if the <code>attributes</code> or the <code>map</code>
* is a <code>null</code> value
*/
public SQLOutputImpl(Vector<?> attributes, Map<String,?> map)
throws SQLException
{
if ((attributes == null) || (map == null)) {
throw new SQLException("Cannot instantiate a SQLOutputImpl " +
"instance with null parameters");
}
this.attribs = attributes;
this.map = map;
}
//================================================================
// Methods for writing attributes to the stream of SQL data.
// These methods correspond to the column-accessor methods of
// java.sql.ResultSet.
//================================================================
/**
* Writes a <code>String</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>CHAR</code>, <code>VARCHAR</code>, or
* <code>LONGVARCHAR</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeString(String x) throws SQLException {
//System.out.println("Adding :"+x);
attribs.add(x);
}
/**
* Writes a <code>boolean</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>BIT</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeBoolean(boolean x) throws SQLException {
attribs.add(Boolean.valueOf(x));
}
/**
* Writes a <code>byte</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>BIT</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeByte(byte x) throws SQLException {
attribs.add(Byte.valueOf(x));
}
/**
* Writes a <code>short</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>SMALLINT</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeShort(short x) throws SQLException {
attribs.add(Short.valueOf(x));
}
/**
* Writes an <code>int</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>INTEGER</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeInt(int x) throws SQLException {
attribs.add(Integer.valueOf(x));
}
/**
* Writes a <code>long</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>BIGINT</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeLong(long x) throws SQLException {
attribs.add(Long.valueOf(x));
}
/**
* Writes a <code>float</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>REAL</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeFloat(float x) throws SQLException {
attribs.add(Float.valueOf(x));
}
/**
* Writes a <code>double</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>DOUBLE</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeDouble(double x) throws SQLException{
attribs.add(Double.valueOf(x));
}
/**
* Writes a <code>java.math.BigDecimal</code> object in the Java programming
* language to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>NUMERIC</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeBigDecimal(java.math.BigDecimal x) throws SQLException{
attribs.add(x);
}
/**
* Writes an array of <code>bytes</code> in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>VARBINARY</code> or <code>LONGVARBINARY</code>
* before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeBytes(byte[] x) throws SQLException {
attribs.add(x);
}
/**
* Writes a <code>java.sql.Date</code> object in the Java programming
* language to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>DATE</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeDate(java.sql.Date x) throws SQLException {
attribs.add(x);
}
/**
* Writes a <code>java.sql.Time</code> object in the Java programming
* language to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>TIME</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeTime(java.sql.Time x) throws SQLException {
attribs.add(x);
}
/**
* Writes a <code>java.sql.Timestamp</code> object in the Java programming
* language to this <code>SQLOutputImpl</code> object. The driver converts
* it to an SQL <code>TIMESTAMP</code> before returning it to the database.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeTimestamp(java.sql.Timestamp x) throws SQLException {
attribs.add(x);
}
/**
* Writes a stream of Unicode characters to this
* <code>SQLOutputImpl</code> object. The driver will do any necessary
* conversion from Unicode to the database <code>CHAR</code> format.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeCharacterStream(java.io.Reader x) throws SQLException {
BufferedReader bufReader = new BufferedReader(x);
try {
int i;
while( (i = bufReader.read()) != -1 ) {
char ch = (char)i;
StringBuffer strBuf = new StringBuffer();
strBuf.append(ch);
String str = new String(strBuf);
String strLine = bufReader.readLine();
writeString(str.concat(strLine));
}
} catch(IOException ioe) {
}
}
/**
* Writes a stream of ASCII characters to this
* <code>SQLOutputImpl</code> object. The driver will do any necessary
* conversion from ASCII to the database <code>CHAR</code> format.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeAsciiStream(java.io.InputStream x) throws SQLException {
BufferedReader bufReader = new BufferedReader(new InputStreamReader(x));
try {
int i;
while( (i=bufReader.read()) != -1 ) {
char ch = (char)i;
StringBuffer strBuf = new StringBuffer();
strBuf.append(ch);
String str = new String(strBuf);
String strLine = bufReader.readLine();
writeString(str.concat(strLine));
}
}catch(IOException ioe) {
throw new SQLException(ioe.getMessage());
}
}
/**
* Writes a stream of uninterpreted bytes to this <code>SQLOutputImpl</code>
* object.
*
* @param x the value to pass to the database
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeBinaryStream(java.io.InputStream x) throws SQLException {
BufferedReader bufReader = new BufferedReader(new InputStreamReader(x));
try {
int i;
while( (i=bufReader.read()) != -1 ) {
char ch = (char)i;
StringBuffer strBuf = new StringBuffer();
strBuf.append(ch);
String str = new String(strBuf);
String strLine = bufReader.readLine();
writeString(str.concat(strLine));
}
} catch(IOException ioe) {
throw new SQLException(ioe.getMessage());
}
}
//================================================================
// Methods for writing items of SQL user-defined types to the stream.
// These methods pass objects to the database as values of SQL
// Structured Types, Distinct Types, Constructed Types, and Locator
// Types. They decompose the Java object(s) and write leaf data
// items using the methods above.
//================================================================
/**
* Writes to the stream the data contained in the given
* <code>SQLData</code> object.
* When the <code>SQLData</code> object is <code>null</code>, this
* method writes an SQL <code>NULL</code> to the stream.
* Otherwise, it calls the <code>SQLData.writeSQL</code>
* method of the given object, which
* writes the object's attributes to the stream.
* <P>
* The implementation of the method <code>SQLData.writeSQ</code>
* calls the appropriate <code>SQLOutputImpl.writeXXX</code> method(s)
* for writing each of the object's attributes in order.
* The attributes must be read from an <code>SQLInput</code>
* input stream and written to an <code>SQLOutputImpl</code>
* output stream in the same order in which they were
* listed in the SQL definition of the user-defined type.
*
* @param x the object representing data of an SQL structured or
* distinct type
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeObject(SQLData x) throws SQLException {
/*
* Except for the types that are passed as objects
* this seems to be the only way for an object to
* get a null value for a field in a structure.
*
* Note: this means that the class defining SQLData
* will need to track if a field is SQL null for itself
*/
if (x == null) {
attribs.add(null);
} else {
/*
* We have to write out a SerialStruct that contains
* the name of this class otherwise we don't know
* what to re-instantiate during readSQL()
*/
attribs.add(new SerialStruct(x, map));
}
}
/**
* Writes a <code>Ref</code> object in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to a serializable <code>SerialRef</code> SQL <code>REF</code> value
* before returning it to the database.
*
* @param x an object representing an SQL <code>REF</code> value
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeRef(Ref x) throws SQLException {
if (x == null) {
attribs.add(null);
} else {
attribs.add(new SerialRef(x));
}
}
/**
* Writes a <code>Blob</code> object in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to a serializable <code>SerialBlob</code> SQL <code>BLOB</code> value
* before returning it to the database.
*
* @param x an object representing an SQL <code>BLOB</code> value
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeBlob(Blob x) throws SQLException {
if (x == null) {
attribs.add(null);
} else {
attribs.add(new SerialBlob(x));
}
}
/**
* Writes a <code>Clob</code> object in the Java programming language
* to this <code>SQLOutputImpl</code> object. The driver converts
* it to a serializable <code>SerialClob</code> SQL <code>CLOB</code> value
* before returning it to the database.
*
* @param x an object representing an SQL <code>CLOB</code> value
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeClob(Clob x) throws SQLException {
if (x == null) {
attribs.add(null);
} else {
attribs.add(new SerialClob(x));
}
}
/**
* Writes a <code>Struct</code> object in the Java
* programming language to this <code>SQLOutputImpl</code>
* object. The driver converts this value to an SQL structured type
* before returning it to the database.
* <P>
* This method should be used when an SQL structured type has been
* mapped to a <code>Struct</code> object in the Java programming
* language (the standard mapping). The method
* <code>writeObject</code> should be used if an SQL structured type
* has been custom mapped to a class in the Java programming language.
*
* @param x an object representing the attributes of an SQL structured type
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeStruct(Struct x) throws SQLException {
SerialStruct s = new SerialStruct(x,map);;
attribs.add(s);
}
/**
* Writes an <code>Array</code> object in the Java
* programming language to this <code>SQLOutputImpl</code>
* object. The driver converts this value to a serializable
* <code>SerialArray</code> SQL <code>ARRAY</code>
* value before returning it to the database.
*
* @param x an object representing an SQL <code>ARRAY</code> value
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeArray(Array x) throws SQLException {
if (x == null) {
attribs.add(null);
} else {
attribs.add(new SerialArray(x, map));
}
}
/**
* Writes an <code>java.sql.Type.DATALINK</code> object in the Java
* programming language to this <code>SQLOutputImpl</code> object. The
* driver converts this value to a serializable <code>SerialDatalink</code>
* SQL <code>DATALINK</code> value before return it to the database.
*
* @param url an object representing a SQL <code>DATALINK</code> value
* @throws SQLException if the <code>SQLOutputImpl</code> object is in
* use by a <code>SQLData</code> object attempting to write the attribute
* values of a UDT to the database.
*/
@SuppressWarnings("unchecked")
public void writeURL(java.net.URL url) throws SQLException {
if (url == null) {
attribs.add(null);
} else {
attribs.add(new SerialDatalink(url));
}
}
/**
* Writes the next attribute to the stream as a <code>String</code>
* in the Java programming language. The driver converts this to a
* SQL <code>NCHAR</code> or
* <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value
* (depending on the argument's
* size relative to the driver's limits on <code>NVARCHAR</code> values)
* when it sends it to the stream.
*
* @param x the value to pass to the database
* @exception SQLException if a database access error occurs
* @since 1.6
*/
@SuppressWarnings("unchecked")
public void writeNString(String x) throws SQLException {
attribs.add(x);
}
/**
* Writes an SQL <code>NCLOB</code> value to the stream.
*
* @param x a <code>NClob</code> object representing data of an SQL
* <code>NCLOB</code> value
*
* @exception SQLException if a database access error occurs
* @since 1.6
*/
@SuppressWarnings("unchecked")
public void writeNClob(NClob x) throws SQLException {
attribs.add(x);
}
/**
* Writes an SQL <code>ROWID</code> value to the stream.
*
* @param x a <code>RowId</code> object representing data of an SQL
* <code>ROWID</code> value
*
* @exception SQLException if a database access error occurs
* @since 1.6
*/
@SuppressWarnings("unchecked")
public void writeRowId(RowId x) throws SQLException {
attribs.add(x);
}
/**
* Writes an SQL <code>XML</code> value to the stream.
*
* @param x a <code>SQLXML</code> object representing data of an SQL
* <code>XML</code> value
*
* @exception SQLException if a database access error occurs
* @since 1.6
*/
@SuppressWarnings("unchecked")
public void writeSQLXML(SQLXML x) throws SQLException {
attribs.add(x);
}
}

View File

@@ -0,0 +1,660 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.sql.*;
import java.io.*;
import java.util.Map;
import java.net.URL;
import java.util.Arrays;
/**
* A serialized version of an <code>Array</code>
* object, which is the mapping in the Java programming language of an SQL
* <code>ARRAY</code> value.
* <P>
* The <code>SerialArray</code> class provides a constructor for creating
* a <code>SerialArray</code> instance from an <code>Array</code> object,
* methods for getting the base type and the SQL name for the base type, and
* methods for copying all or part of a <code>SerialArray</code> object.
* <P>
*
* Note: In order for this class to function correctly, a connection to the
* data source
* must be available in order for the SQL <code>Array</code> 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.
*
* <h3> Thread safety </h3>
*
* 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 <code>Object</code>
* in the Java programming language that represents an element
* in the SQL <code>ARRAY</code> value.
* @serial
*/
private Object[] elements;
/**
* The SQL type of the elements in this <code>SerialArray</code> object. The
* type is expressed as one of the constants from the class
* <code>java.sql.Types</code>.
* @serial
*/
private int baseType;
/**
* The type name used by the DBMS for the elements in the SQL <code>ARRAY</code>
* value that this <code>SerialArray</code> object represents.
* @serial
*/
private String baseTypeName;
/**
* The number of elements in this <code>SerialArray</code> object, which
* is also the number of elements in the SQL <code>ARRAY</code> value
* that this <code>SerialArray</code> object represents.
* @serial
*/
private int len;
/**
* Constructs a new <code>SerialArray</code> object from the given
* <code>Array</code> object, using the given type map for the custom
* mapping of each element when the elements are SQL UDTs.
* <P>
* 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.
* <P>
* The new <code>SerialArray</code>
* object contains the same elements as the <code>Array</code> object
* from which it is built, except when the base type is the SQL type
* <code>STRUCT</code>, <code>ARRAY</code>, <code>BLOB</code>,
* <code>CLOB</code>, <code>DATALINK</code> or <code>JAVA_OBJECT</code>.
* In this case, each element in the new
* <code>SerialArray</code> object is the appropriate serialized form,
* that is, a <code>SerialStruct</code>, <code>SerialArray</code>,
* <code>SerialBlob</code>, <code>SerialClob</code>,
* <code>SerialDatalink</code>, or <code>SerialJavaObject</code> object.
* <P>
* Note: (1) The <code>Array</code> object from which a <code>SerialArray</code>
* object is created must have materialized the SQL <code>ARRAY</code> value's
* data on the client before it is passed to the constructor. Otherwise,
* the new <code>SerialArray</code> object will contain no data.
* <p>
* Note: (2) If the <code>Array</code> contains <code>java.sql.Types.JAVA_OBJECT</code>
* types, the <code>SerialJavaObject</code> constructor is called where checks
* are made to ensure this object is serializable.
* <p>
* Note: (3) The <code>Array</code> object supplied to this constructor cannot
* return <code>null</code> for any <code>Array.getArray()</code> methods.
* <code>SerialArray</code> cannot serialize null array values.
*
*
* @param array the <code>Array</code> object to be serialized
* @param map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT (an SQL structured type or
* distinct type) and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped. The <i>map</i>
* parameter does not have any effect for <code>Blob</code>,
* <code>Clob</code>, <code>DATALINK</code>, or
* <code>JAVA_OBJECT</code> types.
* @throws SerialException if an error occurs serializing the
* <code>Array</code> object
* @throws SQLException if a database access error occurs or if the
* <i>array</i> or the <i>map</i> values are <code>null</code>
*/
public SerialArray(Array array, Map<String,Class<?>> map)
throws SerialException, SQLException
{
if ((array == null) || (map == null)) {
throw new SQLException("Cannot instantiate a SerialArray " +
"object with null parameters");
}
if ((elements = (Object[])array.getArray()) == null) {
throw new SQLException("Invalid Array object. Calls to Array.getArray() " +
"return null value which cannot be serialized");
}
elements = (Object[])array.getArray(map);
baseType = array.getBaseType();
baseTypeName = array.getBaseTypeName();
len = elements.length;
switch (baseType) {
case java.sql.Types.STRUCT:
for (int i = 0; i < len; i++) {
elements[i] = new SerialStruct((Struct)elements[i], map);
}
break;
case java.sql.Types.ARRAY:
for (int i = 0; i < len; i++) {
elements[i] = new SerialArray((Array)elements[i], map);
}
break;
case java.sql.Types.BLOB:
for (int i = 0; i < len; i++) {
elements[i] = new SerialBlob((Blob)elements[i]);
}
break;
case java.sql.Types.CLOB:
for (int i = 0; i < len; i++) {
elements[i] = new SerialClob((Clob)elements[i]);
}
break;
case java.sql.Types.DATALINK:
for (int i = 0; i < len; i++) {
elements[i] = new SerialDatalink((URL)elements[i]);
}
break;
case java.sql.Types.JAVA_OBJECT:
for (int i = 0; i < len; i++) {
elements[i] = new SerialJavaObject(elements[i]);
}
}
}
/**
* 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. <p> If {@code free} is called multiple times, the
* subsequent calls to {@code free} are treated as a no-op. </P>
*
* @throws SQLException if an error occurs releasing the SerialArray's resources
* @since 1.6
*/
public void free() throws SQLException {
if (elements != null) {
elements = null;
baseTypeName= null;
}
}
/**
* Constructs a new <code>SerialArray</code> object from the given
* <code>Array</code> object.
* <P>
* This constructor does not do custom mapping. If the base type of the array
* is an SQL structured type and custom mapping is desired, the constructor
* <code>SerialArray(Array array, Map map)</code> should be used.
* <P>
* The new <code>SerialArray</code>
* object contains the same elements as the <code>Array</code> object
* from which it is built, except when the base type is the SQL type
* <code>BLOB</code>,
* <code>CLOB</code>, <code>DATALINK</code> or <code>JAVA_OBJECT</code>.
* In this case, each element in the new
* <code>SerialArray</code> object is the appropriate serialized form,
* that is, a <code>SerialBlob</code>, <code>SerialClob</code>,
* <code>SerialDatalink</code>, or <code>SerialJavaObject</code> object.
* <P>
* Note: (1) The <code>Array</code> object from which a <code>SerialArray</code>
* object is created must have materialized the SQL <code>ARRAY</code> value's
* data on the client before it is passed to the constructor. Otherwise,
* the new <code>SerialArray</code> object will contain no data.
* <p>
* Note: (2) The <code>Array</code> object supplied to this constructor cannot
* return <code>null</code> for any <code>Array.getArray()</code> methods.
* <code>SerialArray</code> cannot serialize <code>null</code> array values.
*
* @param array the <code>Array</code> object to be serialized
* @throws SerialException if an error occurs serializing the
* <code>Array</code> object
* @throws SQLException if a database access error occurs or the
* <i>array</i> parameter is <code>null</code>.
*/
public SerialArray(Array array) throws SerialException, SQLException {
if (array == null) {
throw new SQLException("Cannot instantiate a SerialArray " +
"object with a null Array object");
}
if ((elements = (Object[])array.getArray()) == null) {
throw new SQLException("Invalid Array object. Calls to Array.getArray() " +
"return null value which cannot be serialized");
}
//elements = (Object[])array.getArray();
baseType = array.getBaseType();
baseTypeName = array.getBaseTypeName();
len = elements.length;
switch (baseType) {
case java.sql.Types.BLOB:
for (int i = 0; i < len; i++) {
elements[i] = new SerialBlob((Blob)elements[i]);
}
break;
case java.sql.Types.CLOB:
for (int i = 0; i < len; i++) {
elements[i] = new SerialClob((Clob)elements[i]);
}
break;
case java.sql.Types.DATALINK:
for (int i = 0; i < len; i++) {
elements[i] = new SerialDatalink((URL)elements[i]);
}
break;
case java.sql.Types.JAVA_OBJECT:
for (int i = 0; i < len; i++) {
elements[i] = new SerialJavaObject(elements[i]);
}
break;
}
}
/**
* Returns a new array that is a copy of this <code>SerialArray</code>
* object.
*
* @return a copy of this <code>SerialArray</code> object as an
* <code>Object</code> 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 <code>SerialArray</code>
* object, using the given type map for the custom
* mapping of each element when the elements are SQL UDTs.
* <P>
* 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 map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @return a copy of this <code>SerialArray</code> object as an
* <code>Object</code> 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<String, Class<?>> 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 <code>SerialArray</code> object, starting with the
* element at the given index and containing the given number
* of consecutive elements.
*
* @param index the index into this <code>SerialArray</code> object
* of the first element to be copied;
* the index of the first element is <code>0</code>
* @param count the number of consecutive elements to be copied, starting
* at the given index
* @return a copy of the designated elements in this <code>SerialArray</code>
* object as an <code>Object</code> 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 <code>SerialArray</code> object, starting with the
* element at the given index and containing the given number
* of consecutive elements.
* <P>
* 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 <code>SerialArray</code> object
* of the first element to be copied; the index of the
* first element in the array is <code>0</code>
* @param count the number of consecutive elements to be copied, starting
* at the given index
* @param map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @return a copy of the designated elements in this <code>SerialArray</code>
* object as an <code>Object</code> 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<String,Class<?>> 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 <code>SerialArray</code>
* object. The <code>int</code> returned is one of the constants in the class
* <code>java.sql.Types</code>.
*
* @return one of the constants in <code>java.sql.Types</code>, indicating
* the SQL type of the elements in this <code>SerialArray</code> 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
* <code>SerialArray</code> object.
*
* @return the SQL type name used by the DBMS for the base type of this
* <code>SerialArray</code> object
* @throws SerialException if an error occurs;
* if {@code free} had previously been called on this object
*/
public String getBaseTypeName() throws SerialException {
isValid();
return baseTypeName;
}
/**
* Retrieves a <code>ResultSet</code> object holding the elements of
* the subarray that starts at
* index <i>index</i> and contains up to <i>count</i> successive elements.
* This method uses the connection's type map to map the elements of
* the array if the map contains
* an entry for the base type. Otherwise, the standard mapping is used.
*
* @param index the index into this <code>SerialArray</code> object
* of the first element to be copied; the index of the
* first element in the array is <code>0</code>
* @param count the number of consecutive elements to be copied, starting
* at the given index
* @return a <code>ResultSet</code> object containing the designated
* elements in this <code>SerialArray</code> object, with a
* separate row for each element
* @throws SerialException if called with the cause set to
* {@code UnsupportedOperationException}
*/
public ResultSet getResultSet(long index, int count) throws SerialException {
SerialException se = new SerialException();
se.initCause(new UnsupportedOperationException());
throw se;
}
/**
*
* Retrieves a <code>ResultSet</code> object that contains all of
* the elements of the SQL <code>ARRAY</code>
* value represented by this <code>SerialArray</code> object. This method uses
* the specified map for type map customizations unless the base type of the
* array does not match a user-defined type (UDT) in <i>map</i>, in
* which case it uses the
* standard mapping. This version of the method <code>getResultSet</code>
* uses either the given type map or the standard mapping; it never uses the
* type map associated with the connection.
*
* @param map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @return a <code>ResultSet</code> object containing all of the
* elements in this <code>SerialArray</code> object, with a
* separate row for each element
* @throws SerialException if called with the cause set to
* {@code UnsupportedOperationException}
*/
public ResultSet getResultSet(Map<String, Class<?>> map)
throws SerialException
{
SerialException se = new SerialException();
se.initCause(new UnsupportedOperationException());
throw se;
}
/**
* Retrieves a <code>ResultSet</code> object that contains all of
* the elements in the <code>ARRAY</code> value that this
* <code>SerialArray</code> object represents.
* If appropriate, the elements of the array are mapped using the connection's
* type map; otherwise, the standard mapping is used.
*
* @return a <code>ResultSet</code> object containing all of the
* elements in this <code>SerialArray</code> object, with a
* separate row for each element
* @throws SerialException if called with the cause set to
* {@code UnsupportedOperationException}
*/
public ResultSet getResultSet() throws SerialException {
SerialException se = new SerialException();
se.initCause(new UnsupportedOperationException());
throw se;
}
/**
* Retrieves a result set holding the elements of the subarray that starts at
* Retrieves a <code>ResultSet</code> object that contains a subarray of the
* elements in this <code>SerialArray</code> object, starting at
* index <i>index</i> and containing up to <i>count</i> successive
* elements. This method uses
* the specified map for type map customizations unless the base type of the
* array does not match a user-defined type (UDT) in <i>map</i>, in
* which case it uses the
* standard mapping. This version of the method <code>getResultSet</code> uses
* either the given type map or the standard mapping; it never uses the type
* map associated with the connection.
*
* @param index the index into this <code>SerialArray</code> object
* of the first element to be copied; the index of the
* first element in the array is <code>0</code>
* @param count the number of consecutive elements to be copied, starting
* at the given index
* @param map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @return a <code>ResultSet</code> object containing the designated
* elements in this <code>SerialArray</code> object, with a
* separate row for each element
* @throws SerialException if called with the cause set to
* {@code UnsupportedOperationException}
*/
public ResultSet getResultSet(long index, int count,
Map<String,Class<?>> map)
throws SerialException
{
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
* SerialArray} object whose elements are identical to this object's elements
*
* @param obj The object to compare this {@code SerialArray} against
*
* @return {@code true} if the given object represents a {@code SerialArray}
* equivalent to this SerialArray, {@code false} otherwise
*
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof SerialArray) {
SerialArray sa = (SerialArray)obj;
return baseType == sa.baseType &&
baseTypeName.equals(sa.baseTypeName) &&
Arrays.equals(elements, sa.elements);
}
return false;
}
/**
* Returns a hash code for this SerialArray. The hash code for a
* {@code SerialArray} object is computed using the hash codes
* of the elements of the {@code SerialArray} object
*
* @return a hash code value for this object.
*/
public int hashCode() {
return (((31 + Arrays.hashCode(elements)) * 31 + len) * 31 +
baseType) * 31 + baseTypeName.hashCode();
}
/**
* Returns a clone of this {@code SerialArray}. The copy will contain a
* 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
*/
public Object clone() {
try {
SerialArray sa = (SerialArray) super.clone();
sa.elements = (elements != null) ? Arrays.copyOf(elements, len) : null;
return sa;
} catch (CloneNotSupportedException ex) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* readObject is called to restore the state of the {@code SerialArray} from
* a stream.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
Object[] tmp = (Object[])fields.get("elements", null);
if (tmp == null)
throw new InvalidObjectException("elements is null and should not be!");
elements = tmp.clone();
len = fields.get("len", 0);
if(elements.length != len)
throw new InvalidObjectException("elements is not the expected size");
baseType = fields.get("baseType", 0);
baseTypeName = (String)fields.get("baseTypeName", null);
}
/**
* writeObject is called to save the state of the {@code SerialArray}
* to a stream.
*/
private void writeObject(ObjectOutputStream s)
throws IOException, ClassNotFoundException {
ObjectOutputStream.PutField fields = s.putFields();
fields.put("elements", elements);
fields.put("len", len);
fields.put("baseType", baseType);
fields.put("baseTypeName", baseTypeName);
s.writeFields();
}
/**
* 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 <code>SerialArray</code>
* object.
*/
static final long serialVersionUID = -8466174297270688520L;
}

View File

@@ -0,0 +1,602 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.sql.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.Arrays;
/**
* A serialized mapping in the Java programming language of an SQL
* <code>BLOB</code> value.
* <P>
* The <code>SerialBlob</code> class provides a constructor for creating
* an instance from a <code>Blob</code> object. Note that the
* <code>Blob</code>
* object should have brought the SQL <code>BLOB</code> value's data over
* to the client before a <code>SerialBlob</code> object
* is constructed from it. The data of an SQL <code>BLOB</code> value can
* be materialized on the client as an array of bytes (using the method
* <code>Blob.getBytes</code>) or as a stream of uninterpreted bytes
* (using the method <code>Blob.getBinaryStream</code>).
* <P>
* <code>SerialBlob</code> methods make it possible to make a copy of a
* <code>SerialBlob</code> object as an array of bytes or as a stream.
* They also make it possible to locate a given pattern of bytes or a
* <code>Blob</code> object within a <code>SerialBlob</code> object
* and to update or truncate a <code>Blob</code> object.
*
* <h3> Thread safety </h3>
*
* <p> 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 {
/**
* A serialized array of uninterpreted bytes representing the
* value of this <code>SerialBlob</code> object.
* @serial
*/
private byte[] buf;
/**
* The internal representation of the <code>Blob</code> object on which this
* <code>SerialBlob</code> object is based.
*/
private Blob blob;
/**
* The number of bytes in this <code>SerialBlob</code> object's
* array of bytes.
* @serial
*/
private long len;
/**
* The original number of bytes in this <code>SerialBlob</code> object's
* array of bytes when it was first established.
* @serial
*/
private long origLen;
/**
* Constructs a <code>SerialBlob</code> object that is a serialized version of
* the given <code>byte</code> array.
* <p>
* The new <code>SerialBlob</code> object is initialized with the data from the
* <code>byte</code> array, thus allowing disconnected <code>RowSet</code>
* objects to establish serialized <code>Blob</code> objects without
* touching the data source.
*
* @param b the <code>byte</code> array containing the data for the
* <code>Blob</code> object to be serialized
* @throws SerialException if an error occurs during serialization
* @throws SQLException if a SQL errors occurs
*/
public SerialBlob(byte[] b)
throws SerialException, SQLException {
len = b.length;
buf = new byte[(int)len];
for(int i = 0; i < len; i++) {
buf[i] = b[i];
}
origLen = len;
}
/**
* Constructs a <code>SerialBlob</code> object that is a serialized
* version of the given <code>Blob</code> object.
* <P>
* The new <code>SerialBlob</code> object is initialized with the
* data from the <code>Blob</code> object; therefore, the
* <code>Blob</code> object should have previously brought the
* SQL <code>BLOB</code> value's data over to the client from
* the database. Otherwise, the new <code>SerialBlob</code> object
* will contain no data.
*
* @param blob the <code>Blob</code> object from which this
* <code>SerialBlob</code> object is to be constructed;
* cannot be null.
* @throws SerialException if an error occurs during serialization
* @throws SQLException if the <code>Blob</code> passed to this
* to this constructor is a <code>null</code>.
* @see java.sql.Blob
*/
public SerialBlob (Blob blob)
throws SerialException, SQLException {
if (blob == null) {
throw new SQLException(
"Cannot instantiate a SerialBlob object with a null Blob object");
}
len = blob.length();
buf = blob.getBytes(1, (int)len );
this.blob = blob;
origLen = len;
}
/**
* Copies the specified number of bytes, starting at the given
* position, from this <code>SerialBlob</code> object to
* another array of bytes.
* <P>
* Note that if the given number of bytes to be copied is larger than
* the length of this <code>SerialBlob</code> object's array of
* bytes, the given number will be shortened to the array's length.
*
* @param pos the ordinal position of the first byte in this
* <code>SerialBlob</code> object to be copied;
* numbering starts at <code>1</code>; must not be less
* than <code>1</code> and must be less than or equal
* to the length of this <code>SerialBlob</code> object
* @param length the number of bytes to be copied
* @return an array of bytes that is a copy of a region of this
* <code>SerialBlob</code> 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;
* 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;
}
if (pos < 1 || len - pos < 0 ) {
throw new SerialException("Invalid arguments: position cannot be "
+ "less than 1 or greater than the length of the SerialBlob");
}
pos--; // correct pos to array index
byte[] b = new byte[length];
for (int i = 0; i < length; i++) {
b[i] = this.buf[(int)pos];
pos++;
}
return b;
}
/**
* Retrieves the number of bytes in this <code>SerialBlob</code>
* object's array of bytes.
*
* @return a <code>long</code> indicating the length in bytes of this
* <code>SerialBlob</code> object's array of bytes
* @throws SerialException if an error occurs;
* if {@code free} had previously been called on this object
*/
public long length() throws SerialException {
isValid();
return len;
}
/**
* Returns this <code>SerialBlob</code> object as an input stream.
* Unlike the related method, <code>setBinaryStream</code>,
* a stream is produced regardless of whether the <code>SerialBlob</code>
* was created with a <code>Blob</code> object or a <code>byte</code> array.
*
* @return a <code>java.io.InputStream</code> object that contains
* this <code>SerialBlob</code> object's array of bytes
* @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 {
isValid();
InputStream stream = new ByteArrayInputStream(buf);
return stream;
}
/**
* Returns the position in this <code>SerialBlob</code> object where
* the given pattern of bytes begins, starting the search at the
* specified position.
*
* @param pattern the pattern of bytes for which to search
* @param start the position of the byte in this
* <code>SerialBlob</code> object from which to begin
* the search; the first position is <code>1</code>;
* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object
* @return the position in this <code>SerialBlob</code> object
* where the given pattern begins, starting at the specified
* position; <code>-1</code> if the pattern is not found
* or the given starting position is out of bounds; position
* numbering for the return value starts at <code>1</code>
* @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 <code>BLOB</code>
* value from the database
*/
public long position(byte[] pattern, long start)
throws SerialException, SQLException {
isValid();
if (start < 1 || start > len) {
return -1;
}
int pos = (int)start-1; // internally Blobs are stored as arrays.
int i = 0;
long patlen = pattern.length;
while (pos < len) {
if (pattern[i] == buf[pos]) {
if (i + 1 == patlen) {
return (pos + 1) - (patlen - 1);
}
i++; pos++; // increment pos, and i
} else if (pattern[i] != buf[pos]) {
pos++; // increment pos only
}
}
return -1; // not found
}
/**
* Returns the position in this <code>SerialBlob</code> object where
* the given <code>Blob</code> object begins, starting the search at the
* specified position.
*
* @param pattern the <code>Blob</code> object for which to search;
* @param start the position of the byte in this
* <code>SerialBlob</code> object from which to begin
* the search; the first position is <code>1</code>;
* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object
* @return the position in this <code>SerialBlob</code> object
* where the given <code>Blob</code> object begins, starting
* at the specified position; <code>-1</code> if the pattern is
* not found or the given starting position is out of bounds;
* position numbering for the return value starts at <code>1</code>
* @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 <code>BLOB</code>
* value from the database
*/
public long position(Blob pattern, long start)
throws SerialException, SQLException {
isValid();
return position(pattern.getBytes(1, (int)(pattern.length())), start);
}
/**
* Writes the given array of bytes to the <code>BLOB</code> value that
* this <code>Blob</code> object represents, starting at position
* <code>pos</code>, and returns the number of bytes written.
*
* @param pos the position in the SQL <code>BLOB</code> value at which
* to start writing. The first position is <code>1</code>;
* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object.
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* value that this <code>Blob</code> object represents
* @return the number of bytes written
* @throws SerialException if there is an error accessing the
* <code>BLOB</code> value; or if an invalid position is set; if an
* invalid offset value is set;
* if {@code free} had previously been called on this object
* @throws SQLException if there is an error accessing the <code>BLOB</code>
* value from the database
* @see #getBytes
*/
public int setBytes(long pos, byte[] bytes)
throws SerialException, SQLException {
return setBytes(pos, bytes, 0, bytes.length);
}
/**
* Writes all or part of the given <code>byte</code> array to the
* <code>BLOB</code> value that this <code>Blob</code> object represents
* and returns the number of bytes written.
* Writing starts at position <code>pos</code> in the <code>BLOB</code>
* value; <i>len</i> bytes from the given byte array are written.
*
* @param pos the position in the <code>BLOB</code> object at which
* to start writing. The first position is <code>1</code>;
* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object.
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* value
* @param offset the offset in the <code>byte</code> array at which
* to start reading the bytes. The first offset position is
* <code>0</code>; must not be less than <code>0</code> nor greater
* than the length of the <code>byte</code> array
* @param length the number of bytes to be written to the
* <code>BLOB</code> value from the array of bytes <i>bytes</i>.
*
* @return the number of bytes written
* @throws SerialException if there is an error accessing the
* <code>BLOB</code> 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 <code>SerialBlob</code> length; or the combined
* 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 <code>BLOB</code>
* value from the database.
* @see #getBytes
*/
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");
}
if (pos < 1 || pos > this.length()) {
throw new SerialException("Invalid position in BLOB object set");
}
if ((long)(length) > origLen) {
throw new SerialException("Buffer is not sufficient to hold the value");
}
if ((length + offset) > bytes.length) {
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
"and length that is greater that the Blob buffer");
}
int i = 0;
pos--; // correct to array indexing
while ( i < length || (offset + i +1) < (bytes.length-offset) ) {
this.buf[(int)pos + i] = bytes[offset + i ];
i++;
}
return i;
}
/**
* Retrieves a stream that can be used to write to the <code>BLOB</code>
* value that this <code>Blob</code> object represents. The stream begins
* at position <code>pos</code>. This method forwards the
* <code>setBinaryStream()</code> call to the underlying <code>Blob</code> in
* the event that this <code>SerialBlob</code> object is instantiated with a
* <code>Blob</code>. If this <code>SerialBlob</code> is instantiated with
* a <code>byte</code> array, a <code>SerialException</code> is thrown.
*
* @param pos the position in the <code>BLOB</code> value at which
* to start writing
* @return a <code>java.io.OutputStream</code> object to which data can
* be written
* @throws SQLException if there is an error accessing the
* <code>BLOB</code> value
* @throws SerialException if the SerialBlob in not instantiated with a
* <code>Blob</code> object that supports <code>setBinaryStream()</code>;
* 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 {
throw new SerialException("Unsupported operation. SerialBlob cannot " +
"return a writable binary stream, unless instantiated with a Blob object " +
"that provides a setBinaryStream() implementation");
}
}
/**
* Truncates the <code>BLOB</code> value that this <code>Blob</code>
* object represents to be <code>len</code> bytes in length.
*
* @param length the length, in bytes, to which the <code>BLOB</code>
* value that this <code>Blob</code> 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;
* if {@code free} had previously been called on this object
*/
public void truncate(long length) throws SerialException {
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
* <code>InputStream</code> 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 {@code Blob} is at position 1
* @param length the length in bytes of the partial value to be retrieved
* @return
* <code>InputStream</code> 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 {
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 {@code SeriableBlob} object and releases the
* resources that it holds. The object is invalid once the {@code free}
* method is called. <p> If {@code free} is called multiple times, the
* subsequent calls to {@code free} are treated as a no-op. </P>
*
* @throws SQLException if an error occurs releasing the Blob's resources
* @since 1.6
*/
public void free() throws SQLException {
if (buf != null) {
buf = null;
if (blob != null) {
blob.free();
}
blob = null;
}
}
/**
* Compares this SerialBlob to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* SerialBlob} object that represents the same sequence of bytes as this
* object.
*
* @param obj The object to compare this {@code SerialBlob} against
*
* @return {@code true} if the given object represents a {@code SerialBlob}
* equivalent to this SerialBlob, {@code false} otherwise
*
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof SerialBlob) {
SerialBlob sb = (SerialBlob)obj;
if (this.len == sb.len) {
return Arrays.equals(buf, sb.buf);
}
}
return false;
}
/**
* Returns a hash code for this {@code SerialBlob}.
* @return a hash code value for this object.
*/
public int hashCode() {
return ((31 + Arrays.hashCode(buf)) * 31 + (int)len) * 31 + (int)origLen;
}
/**
* Returns a clone of this {@code SerialBlob}. The copy will contain a
* reference to a clone of the internal byte array, not a reference
* to the original internal byte array of this {@code SerialBlob} object.
* The underlying {@code Blob} object will be set to null.
*
* @return a clone of this SerialBlob
*/
public Object clone() {
try {
SerialBlob sb = (SerialBlob) super.clone();
sb.buf = (buf != null) ? Arrays.copyOf(buf, (int)len) : null;
sb.blob = null;
return sb;
} catch (CloneNotSupportedException ex) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* readObject is called to restore the state of the SerialBlob from
* a stream.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
byte[] tmp = (byte[])fields.get("buf", null);
if (tmp == null)
throw new InvalidObjectException("buf is null and should not be!");
buf = tmp.clone();
len = fields.get("len", 0L);
if (buf.length != len)
throw new InvalidObjectException("buf is not the expected size");
origLen = fields.get("origLen", 0L);
blob = (Blob) fields.get("blob", null);
}
/**
* writeObject is called to save the state of the SerialBlob
* to a stream.
*/
private void writeObject(ObjectOutputStream s)
throws IOException, ClassNotFoundException {
ObjectOutputStream.PutField fields = s.putFields();
fields.put("buf", buf);
fields.put("len", len);
fields.put("origLen", origLen);
// Note: this check to see if it is an instance of Serializable
// is for backwards compatibiity
fields.put("blob", blob instanceof Serializable ? blob : null);
s.writeFields();
}
/**
* 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;
}

View File

@@ -0,0 +1,694 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.sql.*;
import java.io.*;
import java.util.Arrays;
/**
* A serialized mapping in the Java programming language of an SQL
* <code>CLOB</code> value.
* <P>
* The <code>SerialClob</code> class provides a constructor for creating
* an instance from a <code>Clob</code> object. Note that the <code>Clob</code>
* object should have brought the SQL <code>CLOB</code> value's data over
* to the client before a <code>SerialClob</code> object
* is constructed from it. The data of an SQL <code>CLOB</code> value can
* be materialized on the client as a stream of Unicode characters.
* <P>
* <code>SerialClob</code> methods make it possible to get a substring
* from a <code>SerialClob</code> object or to locate the start of
* a pattern of characters.
*
* <h3> Thread safety </h3>
*
* <p> 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 {
/**
* A serialized array of characters containing the data of the SQL
* <code>CLOB</code> value that this <code>SerialClob</code> object
* represents.
*
* @serial
*/
private char buf[];
/**
* Internal Clob representation if SerialClob is initialized with a
* Clob. Null if SerialClob is initialized with a char[].
*/
private Clob clob;
/**
* The length in characters of this <code>SerialClob</code> object's
* internal array of characters.
*
* @serial
*/
private long len;
/**
* The original length in characters of this <code>SerialClob</code>
* object's internal array of characters.
*
* @serial
*/
private long origLen;
/**
* Constructs a <code>SerialClob</code> object that is a serialized version of
* the given <code>char</code> array.
* <p>
* The new <code>SerialClob</code> object is initialized with the data from the
* <code>char</code> array, thus allowing disconnected <code>RowSet</code>
* objects to establish a serialized <code>Clob</code> object without touching
* the data source.
*
* @param ch the char array representing the <code>Clob</code> object to be
* serialized
* @throws SerialException if an error occurs during serialization
* @throws SQLException if a SQL error occurs
*/
public SerialClob(char ch[]) throws SerialException, SQLException {
// %%% JMB. Agreed. Add code here to throw a SQLException if no
// support is available for locatorsUpdateCopy=false
// Serializing locators is not supported.
len = ch.length;
buf = new char[(int)len];
for (int i = 0; i < len ; i++){
buf[i] = ch[i];
}
origLen = len;
clob = null;
}
/**
* Constructs a <code>SerialClob</code> object that is a serialized
* version of the given <code>Clob</code> object.
* <P>
* The new <code>SerialClob</code> object is initialized with the
* data from the <code>Clob</code> object; therefore, the
* <code>Clob</code> object should have previously brought the
* SQL <code>CLOB</code> value's data over to the client from
* the database. Otherwise, the new <code>SerialClob</code> object
* object will contain no data.
* <p>
* Note: The <code>Clob</code> object supplied to this constructor must
* return non-null for both the <code>Clob.getCharacterStream()</code>
* and <code>Clob.getAsciiStream</code> methods. This <code>SerialClob</code>
* constructor cannot serialize a <code>Clob</code> object in this instance
* and will throw an <code>SQLException</code> object.
*
* @param clob the <code>Clob</code> object from which this
* <code>SerialClob</code> object is to be constructed; cannot be null
* @throws SerialException if an error occurs during serialization
* @throws SQLException if a SQL error occurs in capturing the CLOB;
* if the <code>Clob</code> object is a null; or if either of the
* <code>Clob.getCharacterStream()</code> and <code>Clob.getAsciiStream()</code>
* methods on the <code>Clob</code> returns a null
* @see java.sql.Clob
*/
public SerialClob(Clob clob) throws SerialException, SQLException {
if (clob == null) {
throw new SQLException("Cannot instantiate a SerialClob " +
"object with a null Clob object");
}
len = clob.length();
this.clob = clob;
buf = new char[(int)len];
int read = 0;
int offset = 0;
try (Reader charStream = clob.getCharacterStream()) {
if (charStream == null) {
throw new SQLException("Invalid Clob object. The call to getCharacterStream " +
"returned null which cannot be serialized.");
}
// Note: get an ASCII stream in order to null-check it,
// even though we don't do anything with it.
try (InputStream asciiStream = clob.getAsciiStream()) {
if (asciiStream == null) {
throw new SQLException("Invalid Clob object. The call to getAsciiStream " +
"returned null which cannot be serialized.");
}
}
try (Reader reader = new BufferedReader(charStream)) {
do {
read = reader.read(buf, offset, (int)(len - offset));
offset += read;
} while (read > 0);
}
} catch (java.io.IOException ex) {
throw new SerialException("SerialClob: " + ex.getMessage());
}
origLen = len;
}
/**
* Retrieves the number of characters in this <code>SerialClob</code>
* object's array of characters.
*
* @return a <code>long</code> indicating the length in characters of this
* <code>SerialClob</code> object's array of character
* @throws SerialException if an error occurs;
* if {@code free} had previously been called on this object
*/
public long length() throws SerialException {
isValid();
return len;
}
/**
* Returns this <code>SerialClob</code> object's data as a stream
* of Unicode characters. Unlike the related method, <code>getAsciiStream</code>,
* a stream is produced regardless of whether the <code>SerialClob</code> object
* was created with a <code>Clob</code> object or a <code>char</code> array.
*
* @return a <code>java.io.Reader</code> object containing this
* <code>SerialClob</code> object's data
* @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);
}
/**
* Retrieves the <code>CLOB</code> value designated by this <code>SerialClob</code>
* object as an ascii stream. This method forwards the <code>getAsciiStream</code>
* call to the underlying <code>Clob</code> object in the event that this
* <code>SerialClob</code> object is instantiated with a <code>Clob</code>
* object. If this <code>SerialClob</code> object is instantiated with
* a <code>char</code> array, a <code>SerialException</code> object is thrown.
*
* @return a <code>java.io.InputStream</code> object containing
* this <code>SerialClob</code> object's data
* @throws SerialException if this {@code SerialClob} object was not
* instantiated with a <code>Clob</code> object;
* if {@code free} had previously been called on this object
* @throws SQLException if there is an error accessing the
* <code>CLOB</code> value represented by the <code>Clob</code> object
* that was used to create this <code>SerialClob</code> object
*/
public java.io.InputStream getAsciiStream() throws SerialException, SQLException {
isValid();
if (this.clob != null) {
return this.clob.getAsciiStream();
} else {
throw new SerialException("Unsupported operation. SerialClob cannot " +
"return a the CLOB value as an ascii stream, unless instantiated " +
"with a fully implemented Clob object.");
}
}
/**
* Returns a copy of the substring contained in this
* <code>SerialClob</code> object, starting at the given position
* and continuing for the specified number or characters.
*
* @param pos the position of the first character in the substring
* to be copied; the first character of the
* <code>SerialClob</code> object is at position
* <code>1</code>; must not be less than <code>1</code>,
* and the sum of the starting position and the length
* of the substring must be less than the length of this
* <code>SerialClob</code> object
* @param length the number of characters in the substring to be
* returned; must not be greater than the length of
* this <code>SerialClob</code> object, and the
* sum of the starting position and the length
* of the substring must be less than the length of this
* <code>SerialClob</code> object
* @return a <code>String</code> object containing a substring of
* this <code>SerialClob</code> 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;
* 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 SerialClob object set");
}
if ((pos-1) + length > this.length()) {
throw new SerialException("Invalid position and substring length");
}
try {
return new String(buf, (int)pos - 1, length);
} catch (StringIndexOutOfBoundsException e) {
throw new SerialException("StringIndexOutOfBoundsException: " +
e.getMessage());
}
}
/**
* Returns the position in this <code>SerialClob</code> object
* where the given <code>String</code> object begins, starting
* the search at the specified position. This method returns
* <code>-1</code> if the pattern is not found.
*
* @param searchStr the <code>String</code> object for which to
* search
* @param start the position in this <code>SerialClob</code> object
* at which to start the search; the first position is
* <code>1</code>; must not be less than <code>1</code> nor
* greater than the length of this <code>SerialClob</code> object
* @return the position at which the given <code>String</code> object
* begins, starting the search at the specified position;
* <code>-1</code> if the given <code>String</code> object is
* not found or the starting position is out of bounds; position
* numbering for the return value starts at <code>1</code>
* @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;
}
char pattern[] = searchStr.toCharArray();
int pos = (int)start-1;
int i = 0;
long patlen = pattern.length;
while (pos < len) {
if (pattern[i] == buf[pos]) {
if (i + 1 == patlen) {
return (pos + 1) - (patlen - 1);
}
i++; pos++; // increment pos, and i
} else if (pattern[i] != buf[pos]) {
pos++; // increment pos only
}
}
return -1; // not found
}
/**
* Returns the position in this <code>SerialClob</code> object
* where the given <code>Clob</code> signature begins, starting
* the search at the specified position. This method returns
* <code>-1</code> if the pattern is not found.
*
* @param searchStr the <code>Clob</code> object for which to search
* @param start the position in this <code>SerialClob</code> object
* at which to begin the search; the first position is
* <code>1</code>; must not be less than <code>1</code> nor
* greater than the length of this <code>SerialClob</code> object
* @return the position at which the given <code>Clob</code>
* object begins in this <code>SerialClob</code> object,
* at or after the specified starting position
* @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);
}
/**
* Writes the given Java <code>String</code> to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents, at the position
* <code>pos</code>.
*
* @param pos the position at which to start writing to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents; the first
* position is <code>1</code>; must not be less than <code>1</code> nor
* greater than the length of this <code>SerialClob</code> object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents
* @return the number of characters written
* @throws SerialException if there is an error accessing the
* <code>CLOB</code> 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 <code>SerialClob</code> length; or the combined
* 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()));
}
/**
* Writes <code>len</code> characters of <code>str</code>, starting
* at character <code>offset</code>, to the <code>CLOB</code> value
* that this <code>Clob</code> represents.
*
* @param pos the position at which to start writing to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents; the first
* position is <code>1</code>; must not be less than <code>1</code> nor
* greater than the length of this <code>SerialClob</code> object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>Clob</code> object represents
* @param offset the offset into <code>str</code> to start reading
* the characters to be written
* @param length the number of characters to be written
* @return the number of characters written
* @throws SerialException if there is an error accessing the
* <code>CLOB</code> 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 <code>SerialClob</code> length; or the combined
* 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();
if (offset < 0 || offset > str.length()) {
throw new SerialException("Invalid offset in byte array set");
}
if (pos < 1 || pos > this.length()) {
throw new SerialException("Invalid position in Clob object set");
}
if ((long)(length) > origLen) {
throw new SerialException("Buffer is not sufficient to hold the value");
}
if ((length + offset) > str.length()) {
// need check to ensure length + offset !> bytes.length
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
" and length that is greater that the Blob buffer");
}
int i = 0;
pos--; //values in the array are at position one less
while ( i < length || (offset + i +1) < (str.length() - offset ) ) {
this.buf[(int)pos + i ] = cPattern[offset + i ];
i++;
}
return i;
}
/**
* Retrieves a stream to be used to write Ascii characters to the
* <code>CLOB</code> value that this <code>SerialClob</code> object represents,
* starting at position <code>pos</code>. This method forwards the
* <code>setAsciiStream()</code> call to the underlying <code>Clob</code> object in
* the event that this <code>SerialClob</code> object is instantiated with a
* <code>Clob</code> object. If this <code>SerialClob</code> object is instantiated
* with a <code>char</code> array, a <code>SerialException</code> object is thrown.
*
* @param pos the position at which to start writing to the
* <code>CLOB</code> object
* @return the stream to which ASCII encoded characters can be written
* @throws SerialException if SerialClob is not instantiated with a
* Clob object;
* if the {@code free} method had been previously called on this object
* @throws SQLException if there is an error accessing the
* <code>CLOB</code> value
* @see #getAsciiStream
*/
public java.io.OutputStream setAsciiStream(long pos)
throws SerialException, SQLException {
isValid();
if (this.clob != null) {
return this.clob.setAsciiStream(pos);
} else {
throw new SerialException("Unsupported operation. SerialClob cannot " +
"return a writable ascii stream\n unless instantiated with a Clob object " +
"that has a setAsciiStream() implementation");
}
}
/**
* Retrieves a stream to be used to write a stream of Unicode characters
* to the <code>CLOB</code> value that this <code>SerialClob</code> object
* represents, at position <code>pos</code>. This method forwards the
* <code>setCharacterStream()</code> call to the underlying <code>Clob</code>
* object in the event that this <code>SerialClob</code> object is instantiated with a
* <code>Clob</code> object. If this <code>SerialClob</code> object is instantiated with
* a <code>char</code> array, a <code>SerialException</code> is thrown.
*
* @param pos the position at which to start writing to the
* <code>CLOB</code> value
*
* @return a stream to which Unicode encoded characters can be written
* @throws SerialException if the SerialClob is not instantiated with
* a Clob object;
* if the {@code free} method had been previously called on this object
* @throws SQLException if there is an error accessing the
* <code>CLOB</code> value
* @see #getCharacterStream
*/
public java.io.Writer setCharacterStream(long pos)
throws SerialException, SQLException {
isValid();
if (this.clob != null) {
return this.clob.setCharacterStream(pos);
} else {
throw new SerialException("Unsupported operation. SerialClob cannot " +
"return a writable character stream\n unless instantiated with a Clob object " +
"that has a setCharacterStream implementation");
}
}
/**
* Truncates the <code>CLOB</code> value that this <code>SerialClob</code>
* object represents so that it has a length of <code>len</code>
* characters.
* <p>
* Truncating a <code>SerialClob</code> object to length 0 has the effect of
* clearing its contents.
*
* @param length the length, in bytes, to which the <code>CLOB</code>
* value should be truncated
* @throws SerialException if there is an error accessing the
* <code>CLOB</code> value;
* if the {@code free} method had been previously called on this object
*/
public void truncate(long length) throws SerialException {
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 {
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 {
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.
* <p>
* If {@code free} is called multiple times, the subsequent
* calls to {@code free} are treated as a no-op.
* </P>
* @throws SQLException if an error occurs releasing
* the Clob's resources
* @since 1.6
*/
public void free() throws SQLException {
if (buf != null) {
buf = null;
if (clob != null) {
clob.free();
}
clob = null;
}
}
/**
* Compares this SerialClob to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* SerialClob} object that represents the same sequence of characters as this
* object.
*
* @param obj The object to compare this {@code SerialClob} against
*
* @return {@code true} if the given object represents a {@code SerialClob}
* equivalent to this SerialClob, {@code false} otherwise
*
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof SerialClob) {
SerialClob sc = (SerialClob)obj;
if (this.len == sc.len) {
return Arrays.equals(buf, sc.buf);
}
}
return false;
}
/**
* Returns a hash code for this {@code SerialClob}.
* @return a hash code value for this object.
*/
public int hashCode() {
return ((31 + Arrays.hashCode(buf)) * 31 + (int)len) * 31 + (int)origLen;
}
/**
* Returns a clone of this {@code SerialClob}. The copy will contain a
* reference to a clone of the internal character array, not a reference
* to the original internal character array of this {@code SerialClob} object.
* The underlying {@code Clob} object will be set to null.
*
* @return a clone of this SerialClob
*/
public Object clone() {
try {
SerialClob sc = (SerialClob) super.clone();
sc.buf = (buf != null) ? Arrays.copyOf(buf, (int)len) : null;
sc.clob = null;
return sc;
} catch (CloneNotSupportedException ex) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* readObject is called to restore the state of the SerialClob from
* a stream.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
char[] tmp = (char[])fields.get("buf", null);
if (tmp == null)
throw new InvalidObjectException("buf is null and should not be!");
buf = tmp.clone();
len = fields.get("len", 0L);
if (buf.length != len)
throw new InvalidObjectException("buf is not the expected size");
origLen = fields.get("origLen", 0L);
clob = (Clob) fields.get("clob", null);
}
/**
* writeObject is called to save the state of the SerialClob
* to a stream.
*/
private void writeObject(ObjectOutputStream s)
throws IOException, ClassNotFoundException {
ObjectOutputStream.PutField fields = s.putFields();
fields.put("buf", buf);
fields.put("len", len);
fields.put("origLen", origLen);
// Note: this check to see if it is an instance of Serializable
// is for backwards compatibiity
fields.put("clob", clob instanceof Serializable ? clob : null);
s.writeFields();
}
/**
* 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;
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.sql.*;
import java.io.*;
import java.net.URL;
/**
* A serialized mapping in the Java programming language of an SQL
* <code>DATALINK</code> value. A <code>DATALINK</code> value
* references a file outside of the underlying data source that the
* data source manages.
* <P>
* <code>RowSet</code> implementations can use the method <code>RowSet.getURL</code>
* to retrieve a <code>java.net.URL</code> object, which can be used
* to manipulate the external data.
* <pre>
* java.net.URL url = rowset.getURL(1);
* </pre>
*
* <h3> Thread safety </h3>
*
* 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 {
/**
* The extracted URL field retrieved from the DATALINK field.
* @serial
*/
private URL url;
/**
* The SQL type of the elements in this <code>SerialDatalink</code>
* object. The type is expressed as one of the contants from the
* class <code>java.sql.Types</code>.
* @serial
*/
private int baseType;
/**
* The type name used by the DBMS for the elements in the SQL
* <code>DATALINK</code> value that this SerialDatalink object
* represents.
* @serial
*/
private String baseTypeName;
/**
* Constructs a new <code>SerialDatalink</code> object from the given
* <code>java.net.URL</code> object.
* <P>
* @param url the {@code URL} to create the {@code SerialDataLink} from
* @throws SerialException if url parameter is a null
*/
public SerialDatalink(URL url) throws SerialException {
if (url == null) {
throw new SerialException("Cannot serialize empty URL instance");
}
this.url = url;
}
/**
* Returns a new URL that is a copy of this <code>SerialDatalink</code>
* object.
*
* @return a copy of this <code>SerialDatalink</code> object as a
* <code>URL</code> object in the Java programming language.
* @throws SerialException if the <code>URL</code> object cannot be de-serialized
*/
public URL getDatalink() throws SerialException {
URL aURL = null;
try {
aURL = new URL((this.url).toString());
} catch (java.net.MalformedURLException e) {
throw new SerialException("MalformedURLException: " + e.getMessage());
}
return aURL;
}
/**
* Compares this {@code SerialDatalink} to the specified object.
* The result is {@code true} if and only if the argument is not
* {@code null} and is a {@code SerialDatalink} object whose URL is
* identical to this object's URL
*
* @param obj The object to compare this {@code SerialDatalink} against
*
* @return {@code true} if the given object represents a {@code SerialDatalink}
* equivalent to this SerialDatalink, {@code false} otherwise
*
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof SerialDatalink) {
SerialDatalink sdl = (SerialDatalink) obj;
return url.equals(sdl.url);
}
return false;
}
/**
* Returns a hash code for this {@code SerialDatalink}. The hash code for a
* {@code SerialDatalink} object is taken as the hash code of
* the {@code URL} it stores
*
* @return a hash code value for this object.
*/
public int hashCode() {
return 31 + url.hashCode();
}
/**
* Returns a clone of this {@code SerialDatalink}.
*
* @return a clone of this SerialDatalink
*/
public Object clone() {
try {
SerialDatalink sdl = (SerialDatalink) super.clone();
return sdl;
} catch (CloneNotSupportedException ex) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* readObject and writeObject are called to restore the state
* of the {@code SerialDatalink}
* from a stream. Note: we leverage the default Serialized form
*/
/**
* The identifier that assists in the serialization of this
* {@code SerialDatalink} object.
*/
static final long serialVersionUID = 2826907821828733626L;
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.sql.SQLException;
/**
* Indicates and an error with the serialization or de-serialization of
* SQL types such as <code>BLOB, CLOB, STRUCT or ARRAY</code> in
* addition to SQL types such as <code>DATALINK and JAVAOBJECT</code>
*
*/
public class SerialException extends java.sql.SQLException {
/**
* Creates a new <code>SerialException</code> without a
* message.
*/
public SerialException() {
}
/**
* Creates a new <code>SerialException</code> with the
* specified message.
*
* @param msg the detail message
*/
public SerialException(String msg) {
super(msg);
}
static final long serialVersionUID = -489794565168592690L;
}

View File

@@ -0,0 +1,281 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.io.*;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.Vector;
import javax.sql.rowset.RowSetWarning;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil;
/**
* A serializable mapping in the Java programming language of an SQL
* <code>JAVA_OBJECT</code> value. Assuming the Java object
* implements the <code>Serializable</code> interface, this class simply wraps the
* serialization process.
* <P>
* If however, the serialization is not possible because
* the Java object is not immediately serializable, this class will
* attempt to serialize all non-static members to permit the object
* state to be serialized.
* Static or transient fields cannot be serialized; an attempt to serialize
* them will result in a <code>SerialException</code> object being thrown.
*
* <h3> Thread safety </h3>
*
* 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 {
/**
* Placeholder for object to be serialized.
*/
private Object obj;
/**
* Placeholder for all fields in the <code>JavaObject</code> being serialized.
*/
private transient Field[] fields;
/**
* Constructor for <code>SerialJavaObject</code> helper class.
* <p>
*
* @param obj the Java <code>Object</code> to be serialized
* @throws SerialException if the object is found not to be serializable
*/
public SerialJavaObject(Object obj) throws SerialException {
// if any static fields are found, an exception
// should be thrown
// get Class. Object instance should always be available
Class<?> c = obj.getClass();
// determine if object implements Serializable i/f
if (!(obj instanceof java.io.Serializable)) {
setWarning(new RowSetWarning("Warning, the object passed to the constructor does not implement Serializable"));
}
// can only determine public fields (obviously). If
// any of these are static, this should invalidate
// the action of attempting to persist these fields
// in a serialized form
fields = c.getFields();
if (hasStaticFields(fields)) {
throw new SerialException("Located static fields in " +
"object instance. Cannot serialize");
}
this.obj = obj;
}
/**
* Returns an <code>Object</code> that is a copy of this <code>SerialJavaObject</code>
* object.
*
* @return a copy of this <code>SerialJavaObject</code> object as an
* <code>Object</code> in the Java programming language
* @throws SerialException if the instance is corrupt
*/
public Object getObject() throws SerialException {
return this.obj;
}
/**
* Returns an array of <code>Field</code> objects that contains each
* field of the object that this helper class is serializing.
*
* @return an array of <code>Field</code> objects
* @throws SerialException if an error is encountered accessing
* the serialized object
* @throws SecurityException If a security manager, <i>s</i>, is present
* and the caller's class loader is not the same as or an
* ancestor of the class loader for the class of the
* {@linkplain #getObject object} being serialized
* and invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to the package
* of that class.
* @see Class#getFields
*/
@CallerSensitive
public Field[] getFields() throws SerialException {
if (fields != null) {
Class<?> c = this.obj.getClass();
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
/*
* Check if the caller is allowed to access the specified class's package.
* If access is denied, throw a SecurityException.
*/
Class<?> caller = sun.reflect.Reflection.getCallerClass();
if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
c.getClassLoader())) {
ReflectUtil.checkPackageAccess(c);
}
}
return c.getFields();
} else {
throw new SerialException("SerialJavaObject does not contain" +
" a serialized object instance");
}
}
/**
* The identifier that assists in the serialization of this
* <code>SerialJavaObject</code> object.
*/
static final long serialVersionUID = -1465795139032831023L;
/**
* A container for the warnings issued on this <code>SerialJavaObject</code>
* object. When there are multiple warnings, each warning is chained to the
* previous warning.
*/
Vector<RowSetWarning> chain;
/**
* Compares this SerialJavaObject to the specified object.
* The result is {@code true} if and only if the argument
* is not {@code null} and is a {@code SerialJavaObject}
* object that is identical to this object
*
* @param o The object to compare this {@code SerialJavaObject} against
*
* @return {@code true} if the given object represents a {@code SerialJavaObject}
* equivalent to this SerialJavaObject, {@code false} otherwise
*
*/
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof SerialJavaObject) {
SerialJavaObject sjo = (SerialJavaObject) o;
return obj.equals(sjo.obj);
}
return false;
}
/**
* Returns a hash code for this SerialJavaObject. The hash code for a
* {@code SerialJavaObject} object is taken as the hash code of
* the {@code Object} it stores
*
* @return a hash code value for this object.
*/
public int hashCode() {
return 31 + obj.hashCode();
}
/**
* Returns a clone of this {@code SerialJavaObject}.
*
* @return a clone of this SerialJavaObject
*/
public Object clone() {
try {
SerialJavaObject sjo = (SerialJavaObject) super.clone();
sjo.fields = Arrays.copyOf(fields, fields.length);
if (chain != null)
sjo.chain = new Vector<>(chain);
return sjo;
} catch (CloneNotSupportedException ex) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* Registers the given warning.
*/
private void setWarning(RowSetWarning e) {
if (chain == null) {
chain = new Vector<>();
}
chain.add(e);
}
/**
* readObject is called to restore the state of the {@code SerialJavaObject}
* from a stream.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields1 = s.readFields();
@SuppressWarnings("unchecked")
Vector<RowSetWarning> tmp = (Vector<RowSetWarning>)fields1.get("chain", null);
if (tmp != null)
chain = new Vector<>(tmp);
obj = fields1.get("obj", null);
if (obj != null) {
fields = obj.getClass().getFields();
if(hasStaticFields(fields))
throw new IOException("Located static fields in " +
"object instance. Cannot serialize");
} else {
throw new IOException("Object cannot be null!");
}
}
/**
* writeObject is called to save the state of the {@code SerialJavaObject}
* to a stream.
*/
private void writeObject(ObjectOutputStream s)
throws IOException {
ObjectOutputStream.PutField fields = s.putFields();
fields.put("obj", obj);
fields.put("chain", chain);
s.writeFields();
}
/*
* Check to see if there are any Static Fields in this object
*/
private static boolean hasStaticFields(Field[] fields) {
for (Field field : fields) {
if ( field.getModifiers() == Modifier.STATIC) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,257 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.sql.*;
import java.io.*;
import java.util.*;
/**
* A serialized mapping of a <code>Ref</code> object, which is the mapping in the
* Java programming language of an SQL <code>REF</code> value.
* <p>
* The <code>SerialRef</code> class provides a constructor for
* creating a <code>SerialRef</code> instance from a <code>Ref</code>
* object and provides methods for getting and setting the <code>Ref</code> object.
*
* <h3> Thread safety </h3>
*
* 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 {
/**
* String containing the base type name.
* @serial
*/
private String baseTypeName;
/**
* This will store the type <code>Ref</code> as an <code>Object</code>.
*/
private Object object;
/**
* Private copy of the Ref reference.
*/
private Ref reference;
/**
* Constructs a <code>SerialRef</code> object from the given <code>Ref</code>
* object.
*
* @param ref a Ref object; cannot be <code>null</code>
* @throws SQLException if a database access occurs; if <code>ref</code>
* is <code>null</code>; or if the <code>Ref</code> object returns a
* <code>null</code> value base type name.
* @throws SerialException if an error occurs serializing the <code>Ref</code>
* object
*/
public SerialRef(Ref ref) throws SerialException, SQLException {
if (ref == null) {
throw new SQLException("Cannot instantiate a SerialRef object " +
"with a null Ref object");
}
reference = ref;
object = ref;
if (ref.getBaseTypeName() == null) {
throw new SQLException("Cannot instantiate a SerialRef object " +
"that returns a null base type name");
} else {
baseTypeName = ref.getBaseTypeName();
}
}
/**
* Returns a string describing the base type name of the <code>Ref</code>.
*
* @return a string of the base type name of the Ref
* @throws SerialException in no Ref object has been set
*/
public String getBaseTypeName() throws SerialException {
return baseTypeName;
}
/**
* Returns an <code>Object</code> representing the SQL structured type
* to which this <code>SerialRef</code> object refers. The attributes
* of the structured type are mapped according to the given type map.
*
* @param map a <code>java.util.Map</code> object containing zero or
* more entries, with each entry consisting of 1) a <code>String</code>
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @return an object instance resolved from the Ref reference and mapped
* according to the supplied type map
* @throws SerialException if an error is encountered in the reference
* resolution
*/
public Object getObject(java.util.Map<String,Class<?>> map)
throws SerialException
{
map = new Hashtable<String, Class<?>>(map);
if (object != null) {
return map.get(object);
} else {
throw new SerialException("The object is not set");
}
}
/**
* Returns an <code>Object</code> representing the SQL structured type
* to which this <code>SerialRef</code> object refers.
*
* @return an object instance resolved from the Ref reference
* @throws SerialException if an error is encountered in the reference
* resolution
*/
public Object getObject() throws SerialException {
if (reference != null) {
try {
return reference.getObject();
} catch (SQLException e) {
throw new SerialException("SQLException: " + e.getMessage());
}
}
if (object != null) {
return object;
}
throw new SerialException("The object is not set");
}
/**
* Sets the SQL structured type that this <code>SerialRef</code> object
* references to the given <code>Object</code> object.
*
* @param obj an <code>Object</code> representing the SQL structured type
* to be referenced
* @throws SerialException if an error is encountered generating the
* the structured type referenced by this <code>SerialRef</code> object
*/
public void setObject(Object obj) throws SerialException {
try {
reference.setObject(obj);
} catch (SQLException e) {
throw new SerialException("SQLException: " + e.getMessage());
}
object = obj;
}
/**
* Compares this SerialRef to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* SerialRef} object that represents the same object as this
* object.
*
* @param obj The object to compare this {@code SerialRef} against
*
* @return {@code true} if the given object represents a {@code SerialRef}
* equivalent to this SerialRef, {@code false} otherwise
*
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if(obj instanceof SerialRef) {
SerialRef ref = (SerialRef)obj;
return baseTypeName.equals(ref.baseTypeName) &&
object.equals(ref.object);
}
return false;
}
/**
* Returns a hash code for this {@code SerialRef}.
* @return a hash code value for this object.
*/
public int hashCode() {
return (31 + object.hashCode()) * 31 + baseTypeName.hashCode();
}
/**
* Returns a clone of this {@code SerialRef}.
* The underlying {@code Ref} object will be set to null.
*
* @return a clone of this SerialRef
*/
public Object clone() {
try {
SerialRef ref = (SerialRef) super.clone();
ref.reference = null;
return ref;
} catch (CloneNotSupportedException ex) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* readObject is called to restore the state of the SerialRef from
* a stream.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
object = fields.get("object", null);
baseTypeName = (String) fields.get("baseTypeName", null);
reference = (Ref) fields.get("reference", null);
}
/**
* writeObject is called to save the state of the SerialRef
* to a stream.
*/
private void writeObject(ObjectOutputStream s)
throws IOException, ClassNotFoundException {
ObjectOutputStream.PutField fields = s.putFields();
fields.put("baseTypeName", baseTypeName);
fields.put("object", object);
// Note: this check to see if it is an instance of Serializable
// is for backwards compatibiity
fields.put("reference", reference instanceof Serializable ? reference : null);
s.writeFields();
}
/**
* The identifier that assists in the serialization of this <code>SerialRef</code>
* object.
*/
static final long serialVersionUID = -4727123500609662274L;
}

View File

@@ -0,0 +1,347 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.serial;
import java.sql.*;
import javax.sql.*;
import java.io.*;
import java.math.*;
import java.util.Arrays;
import java.util.Map;
import java.util.Vector;
import javax.sql.rowset.*;
/**
* A serialized mapping in the Java programming language of an SQL
* structured type. Each attribute that is not already serialized
* is mapped to a serialized form, and if an attribute is itself
* a structured type, each of its attributes that is not already
* serialized is mapped to a serialized form.
* <P>
* In addition, the structured type is custom mapped to a class in the
* Java programming language if there is such a mapping, as are
* its attributes, if appropriate.
* <P>
* The <code>SerialStruct</code> class provides a constructor for creating
* an instance from a <code>Struct</code> object, a method for retrieving
* the SQL type name of the SQL structured type in the database, and methods
* for retrieving its attribute values.
*
* <h3> Thread safety </h3>
*
* 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 {
/**
* The SQL type name for the structured type that this
* <code>SerialStruct</code> object represents. This is the name
* used in the SQL definition of the SQL structured type.
*
* @serial
*/
private String SQLTypeName;
/**
* An array of <code>Object</code> instances in which each
* element is an attribute of the SQL structured type that this
* <code>SerialStruct</code> object represents. The attributes are
* ordered according to their order in the definition of the
* SQL structured type.
*
* @serial
*/
private Object attribs[];
/**
* Constructs a <code>SerialStruct</code> object from the given
* <code>Struct</code> object, using the given <code>java.util.Map</code>
* object for custom mapping the SQL structured type or any of its
* attributes that are SQL structured types.
*
* @param in an instance of {@code Struct}
* @param map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @throws SerialException if an error occurs
* @see java.sql.Struct
*/
public SerialStruct(Struct in, Map<String,Class<?>> map)
throws SerialException
{
try {
// get the type name
SQLTypeName = in.getSQLTypeName();
System.out.println("SQLTypeName: " + SQLTypeName);
// get the attributes of the struct
attribs = in.getAttributes(map);
/*
* the array may contain further Structs
* and/or classes that have been mapped,
* other types that we have to serialize
*/
mapToSerial(map);
} catch (SQLException e) {
throw new SerialException(e.getMessage());
}
}
/**
* Constructs a <code>SerialStruct</code> object from the
* given <code>SQLData</code> object, using the given type
* map to custom map it to a class in the Java programming
* language. The type map gives the SQL type and the class
* to which it is mapped. The <code>SQLData</code> object
* defines the class to which the SQL type will be mapped.
*
* @param in an instance of the <code>SQLData</code> class
* that defines the mapping of the SQL structured
* type to one or more objects in the Java programming language
* @param map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @throws SerialException if an error occurs
*/
public SerialStruct(SQLData in, Map<String,Class<?>> map)
throws SerialException
{
try {
//set the type name
SQLTypeName = in.getSQLTypeName();
Vector<Object> tmp = new Vector<>();
in.writeSQL(new SQLOutputImpl(tmp, map));
attribs = tmp.toArray();
} catch (SQLException e) {
throw new SerialException(e.getMessage());
}
}
/**
* Retrieves the SQL type name for this <code>SerialStruct</code>
* object. This is the name used in the SQL definition of the
* structured type
*
* @return a <code>String</code> object representing the SQL
* type name for the SQL structured type that this
* <code>SerialStruct</code> object represents
* @throws SerialException if an error occurs
*/
public String getSQLTypeName() throws SerialException {
return SQLTypeName;
}
/**
* Retrieves an array of <code>Object</code> values containing the
* attributes of the SQL structured type that this
* <code>SerialStruct</code> object represents.
*
* @return an array of <code>Object</code> values, with each
* element being an attribute of the SQL structured type
* that this <code>SerialStruct</code> object represents
* @throws SerialException if an error occurs
*/
public Object[] getAttributes() throws SerialException {
Object[] val = this.attribs;
return (val == null) ? null : Arrays.copyOf(val, val.length);
}
/**
* Retrieves the attributes for the SQL structured type that
* this <code>SerialStruct</code> represents as an array of
* <code>Object</code> values, using the given type map for
* custom mapping if appropriate.
*
* @param map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @return an array of <code>Object</code> values, with each
* element being an attribute of the SQL structured
* type that this <code>SerialStruct</code> object
* represents
* @throws SerialException if an error occurs
*/
public Object[] getAttributes(Map<String,Class<?>> map)
throws SerialException
{
Object[] val = this.attribs;
return (val == null) ? null : Arrays.copyOf(val, val.length);
}
/**
* Maps attributes of an SQL structured type that are not
* serialized to a serialized form, using the given type map
* for custom mapping when appropriate. The following types
* in the Java programming language are mapped to their
* serialized forms: <code>Struct</code>, <code>SQLData</code>,
* <code>Ref</code>, <code>Blob</code>, <code>Clob</code>, and
* <code>Array</code>.
* <P>
* This method is called internally and is not used by an
* application programmer.
*
* @param map a <code>java.util.Map</code> object in which
* each entry consists of 1) a <code>String</code> object
* giving the fully qualified name of a UDT and 2) the
* <code>Class</code> object for the <code>SQLData</code> implementation
* that defines how the UDT is to be mapped
* @throws SerialException if an error occurs
*/
private void mapToSerial(Map<String,Class<?>> map) throws SerialException {
try {
for (int i = 0; i < attribs.length; i++) {
if (attribs[i] instanceof Struct) {
attribs[i] = new SerialStruct((Struct)attribs[i], map);
} else if (attribs[i] instanceof SQLData) {
attribs[i] = new SerialStruct((SQLData)attribs[i], map);
} else if (attribs[i] instanceof Blob) {
attribs[i] = new SerialBlob((Blob)attribs[i]);
} else if (attribs[i] instanceof Clob) {
attribs[i] = new SerialClob((Clob)attribs[i]);
} else if (attribs[i] instanceof Ref) {
attribs[i] = new SerialRef((Ref)attribs[i]);
} else if (attribs[i] instanceof java.sql.Array) {
attribs[i] = new SerialArray((java.sql.Array)attribs[i], map);
}
}
} catch (SQLException e) {
throw new SerialException(e.getMessage());
}
return;
}
/**
* Compares this SerialStruct to the specified object. The result is
* {@code true} if and only if the argument is not {@code null} and is a
* {@code SerialStruct} object whose attributes are identical to this
* object's attributes
*
* @param obj The object to compare this {@code SerialStruct} against
*
* @return {@code true} if the given object represents a {@code SerialStruct}
* equivalent to this SerialStruct, {@code false} otherwise
*
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof SerialStruct) {
SerialStruct ss = (SerialStruct)obj;
return SQLTypeName.equals(ss.SQLTypeName) &&
Arrays.equals(attribs, ss.attribs);
}
return false;
}
/**
* Returns a hash code for this {@code SerialStruct}. The hash code for a
* {@code SerialStruct} object is computed using the hash codes
* of the attributes of the {@code SerialStruct} object and its
* {@code SQLTypeName}
*
* @return a hash code value for this object.
*/
public int hashCode() {
return ((31 + Arrays.hashCode(attribs)) * 31) * 31
+ SQLTypeName.hashCode();
}
/**
* Returns a clone of this {@code SerialStruct}. The copy will contain a
* reference to a clone of the underlying attribs array, not a reference
* to the original underlying attribs array of this {@code SerialStruct} object.
*
* @return a clone of this SerialStruct
*/
public Object clone() {
try {
SerialStruct ss = (SerialStruct) super.clone();
ss.attribs = Arrays.copyOf(attribs, attribs.length);
return ss;
} catch (CloneNotSupportedException ex) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* readObject is called to restore the state of the {@code SerialStruct} from
* a stream.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = s.readFields();
Object[] tmp = (Object[])fields.get("attribs", null);
attribs = tmp == null ? null : tmp.clone();
SQLTypeName = (String)fields.get("SQLTypeName", null);
}
/**
* writeObject is called to save the state of the {@code SerialStruct}
* to a stream.
*/
private void writeObject(ObjectOutputStream s)
throws IOException, ClassNotFoundException {
ObjectOutputStream.PutField fields = s.putFields();
fields.put("attribs", attribs);
fields.put("SQLTypeName", SQLTypeName);
s.writeFields();
}
/**
* The identifier that assists in the serialization of this
* <code>SerialStruct</code> object.
*/
static final long serialVersionUID = -8322445504027483372L;
}

View File

@@ -0,0 +1,967 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.spi;
import java.util.logging.*;
import java.util.*;
import java.sql.*;
import javax.sql.*;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.naming.*;
import sun.reflect.misc.ReflectUtil;
/**
* The Service Provider Interface (SPI) mechanism that generates <code>SyncProvider</code>
* instances to be used by disconnected <code>RowSet</code> objects.
* The <code>SyncProvider</code> instances in turn provide the
* <code>javax.sql.RowSetReader</code> object the <code>RowSet</code> object
* needs to populate itself with data and the
* <code>javax.sql.RowSetWriter</code> object it needs to
* propagate changes to its
* data back to the underlying data source.
* <P>
* Because the methods in the <code>SyncFactory</code> class are all static,
* there is only one <code>SyncFactory</code> object
* per Java VM at any one time. This ensures that there is a single source from which a
* <code>RowSet</code> implementation can obtain its <code>SyncProvider</code>
* implementation.
*
* <h3>1.0 Overview</h3>
* The <code>SyncFactory</code> class provides an internal registry of available
* synchronization provider implementations (<code>SyncProvider</code> objects).
* This registry may be queried to determine which
* synchronization providers are available.
* The following line of code gets an enumeration of the providers currently registered.
* <PRE>
* java.util.Enumeration e = SyncFactory.getRegisteredProviders();
* </PRE>
* All standard <code>RowSet</code> implementations must provide at least two providers:
* <UL>
* <LI>an optimistic provider for use with a <code>CachedRowSet</code> implementation
* or an implementation derived from it
* <LI>an XML provider, which is used for reading and writing XML, such as with
* <code>WebRowSet</code> objects
* </UL>
* Note that the JDBC RowSet Implementations include the <code>SyncProvider</code>
* implementations <code>RIOptimisticProvider</code> and <code>RIXmlProvider</code>,
* which satisfy this requirement.
* <P>
* The <code>SyncFactory</code> class provides accessor methods to assist
* applications in determining which synchronization providers are currently
* registered with the <code>SyncFactory</code>.
* <p>
* Other methods let <code>RowSet</code> persistence providers be
* registered or de-registered with the factory mechanism. This
* allows additional synchronization provider implementations to be made
* available to <code>RowSet</code> objects at run time.
* <p>
* Applications can apply a degree of filtering to determine the level of
* synchronization that a <code>SyncProvider</code> implementation offers.
* The following criteria determine whether a provider is
* made available to a <code>RowSet</code> object:
* <ol>
* <li>If a particular provider is specified by a <code>RowSet</code> object, and
* the <code>SyncFactory</code> does not contain a reference to this provider,
* a <code>SyncFactoryException</code> is thrown stating that the synchronization
* provider could not be found.
*
* <li>If a <code>RowSet</code> implementation is instantiated with a specified
* provider and the specified provider has been properly registered, the
* requested provider is supplied. Otherwise a <code>SyncFactoryException</code>
* is thrown.
*
* <li>If a <code>RowSet</code> object does not specify a
* <code>SyncProvider</code> implementation and no additional
* <code>SyncProvider</code> implementations are available, the reference
* implementation providers are supplied.
* </ol>
* <h3>2.0 Registering <code>SyncProvider</code> Implementations</h3>
* <p>
* Both vendors and developers can register <code>SyncProvider</code>
* implementations using one of the following mechanisms.
* <ul>
* <LI><B>Using the command line</B><BR>
* The name of the provider is supplied on the command line, which will add
* the provider to the system properties.
* For example:
* <PRE>
* -Drowset.provider.classname=com.fred.providers.HighAvailabilityProvider
* </PRE>
* <li><b>Using the Standard Properties File</b><BR>
* The reference implementation is targeted
* to ship with J2SE 1.5, which will include an additional resource file
* that may be edited by hand. Here is an example of the properties file
* included in the reference implementation:
* <PRE>
* #Default JDBC RowSet sync providers listing
* #
*
* # Optimistic synchronization provider
* rowset.provider.classname.0=com.sun.rowset.providers.RIOptimisticProvider
* rowset.provider.vendor.0=Oracle Corporation
* rowset.provider.version.0=1.0
*
* # XML Provider using standard XML schema
* rowset.provider.classname.1=com.sun.rowset.providers.RIXMLProvider
* rowset.provider.vendor.1=Oracle Corporation
* rowset.provider.version.1=1.0
* </PRE>
* The <code>SyncFactory</code> checks this file and registers the
* <code>SyncProvider</code> implementations that it contains. A
* developer or vendor can add other implementations to this file.
* For example, here is a possible addition:
* <PRE>
* rowset.provider.classname.2=com.fred.providers.HighAvailabilityProvider
* rowset.provider.vendor.2=Fred, Inc.
* rowset.provider.version.2=1.0
* </PRE>
*
* <li><b>Using a JNDI Context</b><BR>
* Available providers can be registered on a JNDI
* context, and the <code>SyncFactory</code> will attempt to load
* <code>SyncProvider</code> implementations from that JNDI context.
* For example, the following code fragment registers a provider implementation
* on a JNDI context. This is something a deployer would normally do. In this
* example, <code>MyProvider</code> is being registered on a CosNaming
* namespace, which is the namespace used by J2EE resources.
* <PRE>
* import javax.naming.*;
*
* Hashtable svrEnv = new Hashtable();
* srvEnv.put(Context.INITIAL_CONTEXT_FACTORY, "CosNaming");
*
* Context ctx = new InitialContext(svrEnv);
* com.fred.providers.MyProvider = new MyProvider();
* ctx.rebind("providers/MyProvider", syncProvider);
* </PRE>
* </ul>
* Next, an application will register the JNDI context with the
* <code>SyncFactory</code> instance. This allows the <code>SyncFactory</code>
* to browse within the JNDI context looking for <code>SyncProvider</code>
* implementations.
* <PRE>
* Hashtable appEnv = new Hashtable();
* appEnv.put(Context.INITIAL_CONTEXT_FACTORY, "CosNaming");
* appEnv.put(Context.PROVIDER_URL, "iiop://hostname/providers");
* Context ctx = new InitialContext(appEnv);
*
* SyncFactory.registerJNDIContext(ctx);
* </PRE>
* If a <code>RowSet</code> object attempts to obtain a <code>MyProvider</code>
* object, the <code>SyncFactory</code> will try to locate it. First it searches
* for it in the system properties, then it looks in the resource files, and
* finally it checks the JNDI context that has been set. The <code>SyncFactory</code>
* instance verifies that the requested provider is a valid extension of the
* <code>SyncProvider</code> abstract class and then gives it to the
* <code>RowSet</code> object. In the following code fragment, a new
* <code>CachedRowSet</code> object is created and initialized with
* <i>env</i>, which contains the binding to <code>MyProvider</code>.
* <PRE>
* Hashtable env = new Hashtable();
* env.put(SyncFactory.ROWSET_SYNC_PROVIDER, "com.fred.providers.MyProvider");
* CachedRowSet crs = new com.sun.rowset.CachedRowSetImpl(env);
* </PRE>
* Further details on these mechanisms are available in the
* <code>javax.sql.rowset.spi</code> package specification.
*
* @author Jonathan Bruce
* @see javax.sql.rowset.spi.SyncProvider
* @see javax.sql.rowset.spi.SyncFactoryException
*/
public class SyncFactory {
/**
* Creates a new <code>SyncFactory</code> object, which is the singleton
* instance.
* Having a private constructor guarantees that no more than
* one <code>SyncProvider</code> object can exist at a time.
*/
private SyncFactory() {
}
/**
* The standard property-id for a synchronization provider implementation
* name.
*/
public static final String ROWSET_SYNC_PROVIDER =
"rowset.provider.classname";
/**
* The standard property-id for a synchronization provider implementation
* vendor name.
*/
public static final String ROWSET_SYNC_VENDOR =
"rowset.provider.vendor";
/**
* The standard property-id for a synchronization provider implementation
* version tag.
*/
public static final String ROWSET_SYNC_PROVIDER_VERSION =
"rowset.provider.version";
/**
* The standard resource file name.
*/
private static String ROWSET_PROPERTIES = "rowset.properties";
/**
* Permission required to invoke setJNDIContext and setLogger
*/
private static final SQLPermission SET_SYNCFACTORY_PERMISSION =
new SQLPermission("setSyncFactory");
/**
* The initial JNDI context where <code>SyncProvider</code> implementations can
* be stored and from which they can be invoked.
*/
private static Context ic;
/**
* The <code>Logger</code> object to be used by the <code>SyncFactory</code>.
*/
private static volatile Logger rsLogger;
/**
* The registry of available <code>SyncProvider</code> implementations.
* See section 2.0 of the class comment for <code>SyncFactory</code> for an
* explanation of how a provider can be added to this registry.
*/
private static Hashtable<String, SyncProvider> implementations;
/**
* Adds the the given synchronization provider to the factory register. Guidelines
* are provided in the <code>SyncProvider</code> specification for the
* required naming conventions for <code>SyncProvider</code>
* implementations.
* <p>
* Synchronization providers bound to a JNDI context can be
* registered by binding a SyncProvider instance to a JNDI namespace.
*
* <pre>
* {@code
* SyncProvider p = new MySyncProvider();
* InitialContext ic = new InitialContext();
* ic.bind ("jdbc/rowset/MySyncProvider", p);
* } </pre>
*
* Furthermore, an initial JNDI context should be set with the
* <code>SyncFactory</code> using the <code>setJNDIContext</code> method.
* The <code>SyncFactory</code> leverages this context to search for
* available <code>SyncProvider</code> objects bound to the JNDI
* context and its child nodes.
*
* @param providerID A <code>String</code> object with the unique ID of the
* synchronization provider being registered
* @throws SyncFactoryException if an attempt is made to supply an empty
* or null provider name
* @see #setJNDIContext
*/
public static synchronized void registerProvider(String providerID)
throws SyncFactoryException {
ProviderImpl impl = new ProviderImpl();
impl.setClassname(providerID);
initMapIfNecessary();
implementations.put(providerID, impl);
}
/**
* Returns the <code>SyncFactory</code> singleton.
*
* @return the <code>SyncFactory</code> instance
*/
public static SyncFactory getSyncFactory() {
/*
* Using Initialization on Demand Holder idiom as
* Effective Java 2nd Edition,ITEM 71, indicates it is more performant
* than the Double-Check Locking idiom.
*/
return SyncFactoryHolder.factory;
}
/**
* Removes the designated currently registered synchronization provider from the
* Factory SPI register.
*
* @param providerID The unique-id of the synchronization provider
* @throws SyncFactoryException If an attempt is made to
* unregister a SyncProvider implementation that was not registered.
*/
public static synchronized void unregisterProvider(String providerID)
throws SyncFactoryException {
initMapIfNecessary();
if (implementations.containsKey(providerID)) {
implementations.remove(providerID);
}
}
private static String colon = ":";
private static String strFileSep = "/";
private static synchronized void initMapIfNecessary() throws SyncFactoryException {
// Local implementation class names and keys from Properties
// file, translate names into Class objects using Class.forName
// and store mappings
final Properties properties = new Properties();
if (implementations == null) {
implementations = new Hashtable<>();
try {
// check if user is supplying his Synchronisation Provider
// Implementation if not using Oracle's implementation.
// properties.load(new FileInputStream(ROWSET_PROPERTIES));
// The rowset.properties needs to be in jdk/jre/lib when
// integrated with jdk.
// else it should be picked from -D option from command line.
// -Drowset.properties will add to standard properties. Similar
// keys will over-write
/*
* Dependent on application
*/
String strRowsetProperties;
try {
strRowsetProperties = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("rowset.properties");
}
}, null, new PropertyPermission("rowset.properties", "read"));
} catch (Exception ex) {
System.out.println("errorget rowset.properties: " + ex);
strRowsetProperties = null;
};
if (strRowsetProperties != null) {
// Load user's implementation of SyncProvider
// here. -Drowset.properties=/abc/def/pqr.txt
ROWSET_PROPERTIES = strRowsetProperties;
try (FileInputStream fis = new FileInputStream(ROWSET_PROPERTIES)) {
properties.load(fis);
}
parseProperties(properties);
}
/*
* Always available
*/
ROWSET_PROPERTIES = "javax" + strFileSep + "sql" +
strFileSep + "rowset" + strFileSep +
"rowset.properties";
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
try (InputStream stream = (cl == null) ?
ClassLoader.getSystemResourceAsStream(ROWSET_PROPERTIES)
: cl.getResourceAsStream(ROWSET_PROPERTIES)) {
if (stream == null) {
throw new SyncFactoryException("Resource " + ROWSET_PROPERTIES + " not found");
}
properties.load(stream);
}
return null;
});
} catch (PrivilegedActionException ex) {
Throwable e = ex.getException();
if (e instanceof SyncFactoryException) {
throw (SyncFactoryException) e;
} else {
SyncFactoryException sfe = new SyncFactoryException();
sfe.initCause(ex.getException());
throw sfe;
}
}
parseProperties(properties);
// removed else, has properties should sum together
} catch (FileNotFoundException e) {
throw new SyncFactoryException("Cannot locate properties file: " + e);
} catch (IOException e) {
throw new SyncFactoryException("IOException: " + e);
}
/*
* Now deal with -Drowset.provider.classname
* load additional properties from -D command line
*/
properties.clear();
String providerImpls;
try {
providerImpls = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty(ROWSET_SYNC_PROVIDER);
}
}, null, new PropertyPermission(ROWSET_SYNC_PROVIDER, "read"));
} catch (Exception ex) {
providerImpls = null;
}
if (providerImpls != null) {
int i = 0;
if (providerImpls.indexOf(colon) > 0) {
StringTokenizer tokenizer = new StringTokenizer(providerImpls, colon);
while (tokenizer.hasMoreElements()) {
properties.put(ROWSET_SYNC_PROVIDER + "." + i, tokenizer.nextToken());
i++;
}
} else {
properties.put(ROWSET_SYNC_PROVIDER, providerImpls);
}
parseProperties(properties);
}
}
}
/**
* The internal debug switch.
*/
private static boolean debug = false;
/**
* Internal registry count for the number of providers contained in the
* registry.
*/
private static int providerImplIndex = 0;
/**
* Internal handler for all standard property parsing. Parses standard
* ROWSET properties and stores lazy references into the the internal registry.
*/
private static void parseProperties(Properties p) {
ProviderImpl impl = null;
String key = null;
String[] propertyNames = null;
for (Enumeration<?> e = p.propertyNames(); e.hasMoreElements();) {
String str = (String) e.nextElement();
int w = str.length();
if (str.startsWith(SyncFactory.ROWSET_SYNC_PROVIDER)) {
impl = new ProviderImpl();
impl.setIndex(providerImplIndex++);
if (w == (SyncFactory.ROWSET_SYNC_PROVIDER).length()) {
// no property index has been set.
propertyNames = getPropertyNames(false);
} else {
// property index has been set.
propertyNames = getPropertyNames(true, str.substring(w - 1));
}
key = p.getProperty(propertyNames[0]);
impl.setClassname(key);
impl.setVendor(p.getProperty(propertyNames[1]));
impl.setVersion(p.getProperty(propertyNames[2]));
implementations.put(key, impl);
}
}
}
/**
* Used by the parseProperties methods to disassemble each property tuple.
*/
private static String[] getPropertyNames(boolean append) {
return getPropertyNames(append, null);
}
/**
* Disassembles each property and its associated value. Also handles
* overloaded property names that contain indexes.
*/
private static String[] getPropertyNames(boolean append,
String propertyIndex) {
String dot = ".";
String[] propertyNames =
new String[]{SyncFactory.ROWSET_SYNC_PROVIDER,
SyncFactory.ROWSET_SYNC_VENDOR,
SyncFactory.ROWSET_SYNC_PROVIDER_VERSION};
if (append) {
for (int i = 0; i < propertyNames.length; i++) {
propertyNames[i] = propertyNames[i] +
dot +
propertyIndex;
}
return propertyNames;
} else {
return propertyNames;
}
}
/**
* Internal debug method that outputs the registry contents.
*/
private static void showImpl(ProviderImpl impl) {
System.out.println("Provider implementation:");
System.out.println("Classname: " + impl.getClassname());
System.out.println("Vendor: " + impl.getVendor());
System.out.println("Version: " + impl.getVersion());
System.out.println("Impl index: " + impl.getIndex());
}
/**
* Returns the <code>SyncProvider</code> instance identified by <i>providerID</i>.
*
* @param providerID the unique identifier of the provider
* @return a <code>SyncProvider</code> implementation
* @throws SyncFactoryException If the SyncProvider cannot be found,
* the providerID is {@code null}, or
* some error was encountered when trying to invoke this provider.
*/
public static SyncProvider getInstance(String providerID)
throws SyncFactoryException {
if(providerID == null) {
throw new SyncFactoryException("The providerID cannot be null");
}
initMapIfNecessary(); // populate HashTable
initJNDIContext(); // check JNDI context for any additional bindings
ProviderImpl impl = (ProviderImpl) implementations.get(providerID);
if (impl == null) {
// Requested SyncProvider is unavailable. Return default provider.
return new com.sun.rowset.providers.RIOptimisticProvider();
}
try {
ReflectUtil.checkPackageAccess(providerID);
} catch (java.security.AccessControlException e) {
SyncFactoryException sfe = new SyncFactoryException();
sfe.initCause(e);
throw sfe;
}
// Attempt to invoke classname from registered SyncProvider list
Class<?> c = null;
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
/**
* The SyncProvider implementation of the user will be in
* the classpath. We need to find the ClassLoader which loads
* this SyncFactory and try to load the SyncProvider class from
* there.
**/
c = Class.forName(providerID, true, cl);
if (c != null) {
return (SyncProvider) c.newInstance();
} else {
return new com.sun.rowset.providers.RIOptimisticProvider();
}
} catch (IllegalAccessException e) {
throw new SyncFactoryException("IllegalAccessException: " + e.getMessage());
} catch (InstantiationException e) {
throw new SyncFactoryException("InstantiationException: " + e.getMessage());
} catch (ClassNotFoundException e) {
throw new SyncFactoryException("ClassNotFoundException: " + e.getMessage());
}
}
/**
* Returns an Enumeration of currently registered synchronization
* providers. A <code>RowSet</code> implementation may use any provider in
* the enumeration as its <code>SyncProvider</code> object.
* <p>
* At a minimum, the reference synchronization provider allowing
* RowSet content data to be stored using a JDBC driver should be
* possible.
*
* @return Enumeration A enumeration of available synchronization
* providers that are registered with this Factory
* @throws SyncFactoryException If an error occurs obtaining the registered
* providers
*/
public static Enumeration<SyncProvider> getRegisteredProviders()
throws SyncFactoryException {
initMapIfNecessary();
// return a collection of classnames
// of type SyncProvider
return implementations.elements();
}
/**
* Sets the logging object to be used by the <code>SyncProvider</code>
* implementation provided by the <code>SyncFactory</code>. All
* <code>SyncProvider</code> implementations can log their events to
* this object and the application can retrieve a handle to this
* object using the <code>getLogger</code> method.
* <p>
* This method checks to see that there is an {@code SQLPermission}
* object which grants the permission {@code setSyncFactory}
* before allowing the method to succeed. If a
* {@code SecurityManager} exists and its
* {@code checkPermission} method denies calling {@code setLogger},
* this method throws a
* {@code java.lang.SecurityException}.
*
* @param logger A Logger object instance
* @throws java.lang.SecurityException if a security manager exists and its
* {@code checkPermission} method denies calling {@code setLogger}
* @throws NullPointerException if the logger is null
* @see SecurityManager#checkPermission
*/
public static void setLogger(Logger logger) {
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkPermission(SET_SYNCFACTORY_PERMISSION);
}
if(logger == null){
throw new NullPointerException("You must provide a Logger");
}
rsLogger = logger;
}
/**
* Sets the logging object that is used by <code>SyncProvider</code>
* implementations provided by the <code>SyncFactory</code> SPI. All
* <code>SyncProvider</code> implementations can log their events
* to this object and the application can retrieve a handle to this
* object using the <code>getLogger</code> method.
* <p>
* This method checks to see that there is an {@code SQLPermission}
* object which grants the permission {@code setSyncFactory}
* before allowing the method to succeed. If a
* {@code SecurityManager} exists and its
* {@code checkPermission} method denies calling {@code setLogger},
* this method throws a
* {@code java.lang.SecurityException}.
*
* @param logger a Logger object instance
* @param level a Level object instance indicating the degree of logging
* required
* @throws java.lang.SecurityException if a security manager exists and its
* {@code checkPermission} method denies calling {@code setLogger}
* @throws NullPointerException if the logger is null
* @see SecurityManager#checkPermission
* @see LoggingPermission
*/
public static void setLogger(Logger logger, Level level) {
// singleton
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkPermission(SET_SYNCFACTORY_PERMISSION);
}
if(logger == null){
throw new NullPointerException("You must provide a Logger");
}
logger.setLevel(level);
rsLogger = logger;
}
/**
* Returns the logging object for applications to retrieve
* synchronization events posted by SyncProvider implementations.
* @return The {@code Logger} that has been specified for use by
* {@code SyncProvider} implementations
* @throws SyncFactoryException if no logging object has been set.
*/
public static Logger getLogger() throws SyncFactoryException {
Logger result = rsLogger;
// only one logger per session
if (result == null) {
throw new SyncFactoryException("(SyncFactory) : No logger has been set");
}
return result;
}
/**
* Sets the initial JNDI context from which SyncProvider implementations
* can be retrieved from a JNDI namespace
* <p>
* This method checks to see that there is an {@code SQLPermission}
* object which grants the permission {@code setSyncFactory}
* before allowing the method to succeed. If a
* {@code SecurityManager} exists and its
* {@code checkPermission} method denies calling {@code setJNDIContext},
* this method throws a
* {@code java.lang.SecurityException}.
*
* @param ctx a valid JNDI context
* @throws SyncFactoryException if the supplied JNDI context is null
* @throws java.lang.SecurityException if a security manager exists and its
* {@code checkPermission} method denies calling {@code setJNDIContext}
* @see SecurityManager#checkPermission
*/
public static synchronized void setJNDIContext(javax.naming.Context ctx)
throws SyncFactoryException {
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkPermission(SET_SYNCFACTORY_PERMISSION);
}
if (ctx == null) {
throw new SyncFactoryException("Invalid JNDI context supplied");
}
ic = ctx;
}
/**
* Controls JNDI context initialization.
*
* @throws SyncFactoryException if an error occurs parsing the JNDI context
*/
private static synchronized void initJNDIContext() throws SyncFactoryException {
if ((ic != null) && (lazyJNDICtxRefresh == false)) {
try {
parseProperties(parseJNDIContext());
lazyJNDICtxRefresh = true; // touch JNDI namespace once.
} catch (NamingException e) {
e.printStackTrace();
throw new SyncFactoryException("SPI: NamingException: " + e.getExplanation());
} catch (Exception e) {
e.printStackTrace();
throw new SyncFactoryException("SPI: Exception: " + e.getMessage());
}
}
}
/**
* Internal switch indicating whether the JNDI namespace should be re-read.
*/
private static boolean lazyJNDICtxRefresh = false;
/**
* Parses the set JNDI Context and passes bindings to the enumerateBindings
* method when complete.
*/
private static Properties parseJNDIContext() throws NamingException {
NamingEnumeration<?> bindings = ic.listBindings("");
Properties properties = new Properties();
// Hunt one level below context for available SyncProvider objects
enumerateBindings(bindings, properties);
return properties;
}
/**
* Scans each binding on JNDI context and determines if any binding is an
* instance of SyncProvider, if so, add this to the registry and continue to
* scan the current context using a re-entrant call to this method until all
* bindings have been enumerated.
*/
private static void enumerateBindings(NamingEnumeration<?> bindings,
Properties properties) throws NamingException {
boolean syncProviderObj = false; // move to parameters ?
try {
Binding bd = null;
Object elementObj = null;
String element = null;
while (bindings.hasMore()) {
bd = (Binding) bindings.next();
element = bd.getName();
elementObj = bd.getObject();
if (!(ic.lookup(element) instanceof Context)) {
// skip directories/sub-contexts
if (ic.lookup(element) instanceof SyncProvider) {
syncProviderObj = true;
}
}
if (syncProviderObj) {
SyncProvider sync = (SyncProvider) elementObj;
properties.put(SyncFactory.ROWSET_SYNC_PROVIDER,
sync.getProviderID());
syncProviderObj = false; // reset
}
}
} catch (javax.naming.NotContextException e) {
bindings.next();
// Re-entrant call into method
enumerateBindings(bindings, properties);
}
}
/**
* Lazy initialization Holder class used by {@code getSyncFactory}
*/
private static class SyncFactoryHolder {
static final SyncFactory factory = new SyncFactory();
}
}
/**
* Internal class that defines the lazy reference construct for each registered
* SyncProvider implementation.
*/
class ProviderImpl extends SyncProvider {
private String className = null;
private String vendorName = null;
private String ver = null;
private int index;
public void setClassname(String classname) {
className = classname;
}
public String getClassname() {
return className;
}
public void setVendor(String vendor) {
vendorName = vendor;
}
public String getVendor() {
return vendorName;
}
public void setVersion(String providerVer) {
ver = providerVer;
}
public String getVersion() {
return ver;
}
public void setIndex(int i) {
index = i;
}
public int getIndex() {
return index;
}
public int getDataSourceLock() throws SyncProviderException {
int dsLock = 0;
try {
dsLock = SyncFactory.getInstance(className).getDataSourceLock();
} catch (SyncFactoryException sfEx) {
throw new SyncProviderException(sfEx.getMessage());
}
return dsLock;
}
public int getProviderGrade() {
int grade = 0;
try {
grade = SyncFactory.getInstance(className).getProviderGrade();
} catch (SyncFactoryException sfEx) {
//
}
return grade;
}
public String getProviderID() {
return className;
}
/*
public javax.sql.RowSetInternal getRowSetInternal() {
try
{
return SyncFactory.getInstance(className).getRowSetInternal();
} catch(SyncFactoryException sfEx) {
//
}
}
*/
public javax.sql.RowSetReader getRowSetReader() {
RowSetReader rsReader = null;
try {
rsReader = SyncFactory.getInstance(className).getRowSetReader();
} catch (SyncFactoryException sfEx) {
//
}
return rsReader;
}
public javax.sql.RowSetWriter getRowSetWriter() {
RowSetWriter rsWriter = null;
try {
rsWriter = SyncFactory.getInstance(className).getRowSetWriter();
} catch (SyncFactoryException sfEx) {
//
}
return rsWriter;
}
public void setDataSourceLock(int param)
throws SyncProviderException {
try {
SyncFactory.getInstance(className).setDataSourceLock(param);
} catch (SyncFactoryException sfEx) {
throw new SyncProviderException(sfEx.getMessage());
}
}
public int supportsUpdatableView() {
int view = 0;
try {
view = SyncFactory.getInstance(className).supportsUpdatableView();
} catch (SyncFactoryException sfEx) {
//
}
return view;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.spi;
import java.sql.SQLException;
/**
* Indicates an error with <code>SyncFactory</code> mechanism. A disconnected
* RowSet implementation cannot be used without a <code>SyncProvider</code>
* being successfully instantiated
*
* @author Jonathan Bruce
* @see javax.sql.rowset.spi.SyncFactory
* @see javax.sql.rowset.spi.SyncFactoryException
*/
public class SyncFactoryException extends java.sql.SQLException {
/**
* Creates new <code>SyncFactoryException</code> without detail message.
*/
public SyncFactoryException() {
}
/**
* Constructs an <code>SyncFactoryException</code> with the specified
* detail message.
*
* @param msg the detail message.
*/
public SyncFactoryException(String msg) {
super(msg);
}
static final long serialVersionUID = -4354595476433200352L;
}

View File

@@ -0,0 +1,430 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.spi;
import javax.sql.*;
/**
* The synchronization mechanism that provides reader/writer capabilities for
* disconnected <code>RowSet</code> objects.
* A <code>SyncProvider</code> implementation is a class that extends the
* <code>SyncProvider</code> abstract class.
* <P>
* A <code>SyncProvider</code> implementation is
* identified by a unique ID, which is its fully qualified class name.
* This name must be registered with the
* <code>SyncFactory</code> SPI, thus making the implementation available to
* all <code>RowSet</code> implementations.
* The factory mechanism in the reference implementation uses this name to instantiate
* the implementation, which can then provide a <code>RowSet</code> object with its
* reader (a <code>javax.sql.RowSetReader</code> object) and its writer (a
* <code>javax.sql.RowSetWriter</code> object).
* <P>
* The Jdbc <code>RowSet</code> Implementations specification provides two
* reference implementations of the <code>SyncProvider</code> abstract class:
* <code>RIOptimisticProvider</code> and <code>RIXMLProvider</code>.
* The <code>RIOptimisticProvider</code> can set any <code>RowSet</code>
* implementation with a <code>RowSetReader</code> object and a
* <code>RowSetWriter</code> object. However, only the <code>RIXMLProvider</code>
* implementation can set an <code>XmlReader</code> object and an
* <code>XmlWriter</code> object. A <code>WebRowSet</code> object uses the
* <code>XmlReader</code> object to read data in XML format to populate itself with that
* data. It uses the <code>XmlWriter</code> object to write itself to a stream or
* <code>java.io.Writer</code> object in XML format.
*
* <h3>1.0 Naming Convention for Implementations</h3>
* As a guide to naming <code>SyncProvider</code>
* implementations, the following should be noted:
* <UL>
* <li>The name for a <code>SyncProvider</code> implementation
* is its fully qualified class name.
* <li>It is recommended that vendors supply a
* <code>SyncProvider</code> implementation in a package named <code>providers</code>.
* </UL>
* <p>
* For instance, if a vendor named Fred, Inc. offered a
* <code>SyncProvider</code> implementation, you could have the following:
* <PRE>
* Vendor name: Fred, Inc.
* Domain name of vendor: com.fred
* Package name: com.fred.providers
* SyncProvider implementation class name: HighAvailabilityProvider
*
* Fully qualified class name of SyncProvider implementation:
* com.fred.providers.HighAvailabilityProvider
* </PRE>
* <P>
* The following line of code uses the fully qualified name to register
* this implementation with the <code>SyncFactory</code> static instance.
* <PRE>
* SyncFactory.registerProvider(
* "com.fred.providers.HighAvailabilityProvider");
* </PRE>
* <P>
* The default <code>SyncProvider</code> object provided with the reference
* implementation uses the following name:
* <pre>
* com.sun.rowset.providers.RIOptimisticProvider
* </pre>
* <p>
* A vendor can register a <code>SyncProvider</code> implementation class name
* with Oracle Corporation by sending email to jdbc@sun.com.
* Oracle will maintain a database listing the
* available <code>SyncProvider</code> implementations for use with compliant
* <code>RowSet</code> implementations. This database will be similar to the
* one already maintained to list available JDBC drivers.
* <P>
* Vendors should refer to the reference implementation synchronization
* providers for additional guidance on how to implement a new
* <code>SyncProvider</code> implementation.
*
* <h3>2.0 How a <code>RowSet</code> Object Gets Its Provider</h3>
*
* A disconnected <code>Rowset</code> object may get access to a
* <code>SyncProvider</code> object in one of the following two ways:
* <UL>
* <LI>Using a constructor<BR>
* <PRE>
* CachedRowSet crs = new CachedRowSet(
* "com.fred.providers.HighAvailabilitySyncProvider");
* </PRE>
* <LI>Using the <code>setSyncProvider</code> method
* <PRE>
* CachedRowSet crs = new CachedRowSet();
* crs.setSyncProvider("com.fred.providers.HighAvailabilitySyncProvider");
* </PRE>
* </UL>
* <p>
* By default, the reference implementations of the <code>RowSet</code> synchronization
* providers are always available to the Java platform.
* If no other pluggable synchronization providers have been correctly
* registered, the <code>SyncFactory</code> will automatically generate
* an instance of the default <code>SyncProvider</code> reference implementation.
* Thus, in the preceding code fragment, if no implementation named
* <code>com.fred.providers.HighAvailabilitySyncProvider</code> has been
* registered with the <code>SyncFactory</code> instance, <i>crs</i> will be
* assigned the default provider in the reference implementation, which is
* <code>com.sun.rowset.providers.RIOptimisticProvider</code>.
*
* <h3>3.0 Violations and Synchronization Issues</h3>
* If an update between a disconnected <code>RowSet</code> object
* and a data source violates
* the original query or the underlying data source constraints, this will
* result in undefined behavior for all disconnected <code>RowSet</code> implementations
* and their designated <code>SyncProvider</code> implementations.
* Not defining the behavior when such violations occur offers greater flexibility
* for a <code>SyncProvider</code>
* implementation to determine its own best course of action.
* <p>
* A <code>SyncProvider</code> implementation
* may choose to implement a specific handler to
* handle a subset of query violations.
* However if an original query violation or a more general data source constraint
* violation is not handled by the <code>SyncProvider</code> implementation,
* all <code>SyncProvider</code>
* objects must throw a <code>SyncProviderException</code>.
*
* <h3>4.0 Updatable SQL VIEWs</h3>
* It is possible for any disconnected or connected <code>RowSet</code> object to be populated
* from an SQL query that is formulated originally from an SQL <code>VIEW</code>.
* While in many cases it is possible for an update to be performed to an
* underlying view, such an update requires additional metadata, which may vary.
* The <code>SyncProvider</code> class provides two constants to indicate whether
* an implementation supports updating an SQL <code>VIEW</code>.
* <ul>
* <li><code><b>NONUPDATABLE_VIEW_SYNC</b></code> - Indicates that a <code>SyncProvider</code>
* implementation does not support synchronization with an SQL <code>VIEW</code> as the
* underlying source of data for the <code>RowSet</code> object.
* <li><code><b>UPDATABLE_VIEW_SYNC</b></code> - Indicates that a
* <code>SyncProvider</code> implementation
* supports synchronization with an SQL <code>VIEW</code> as the underlying source
* of data.
* </ul>
* <P>
* The default is for a <code>RowSet</code> object not to be updatable if it was
* populated with data from an SQL <code>VIEW</code>.
*
* <h3>5.0 <code>SyncProvider</code> Constants</h3>
* The <code>SyncProvider</code> class provides three sets of constants that
* are used as return values or parameters for <code>SyncProvider</code> methods.
* <code>SyncProvider</code> objects may be implemented to perform synchronization
* between a <code>RowSet</code> object and its underlying data source with varying
* degrees of of care. The first group of constants indicate how synchronization
* is handled. For example, <code>GRADE_NONE</code> indicates that a
* <code>SyncProvider</code> object will not take any care to see what data is
* valid and will simply write the <code>RowSet</code> data to the data source.
* <code>GRADE_MODIFIED_AT_COMMIT</code> indicates that the provider will check
* only modified data for validity. Other grades check all data for validity
* or set locks when data is modified or loaded.
* <OL>
* <LI>Constants to indicate the synchronization grade of a
* <code>SyncProvider</code> object
* <UL>
* <LI>SyncProvider.GRADE_NONE
* <LI>SyncProvider.GRADE_MODIFIED_AT_COMMIT
* <LI>SyncProvider.GRADE_CHECK_ALL_AT_COMMIT
* <LI>SyncProvider.GRADE_LOCK_WHEN_MODIFIED
* <LI>SyncProvider.GRADE_LOCK_WHEN_LOADED
* </UL>
* <LI>Constants to indicate what locks are set on the data source
* <UL>
* <LI>SyncProvider.DATASOURCE_NO_LOCK
* <LI>SyncProvider.DATASOURCE_ROW_LOCK
* <LI>SyncProvider.DATASOURCE_TABLE_LOCK
* <LI>SyncProvider.DATASOURCE_DB_LOCK
* </UL>
* <LI>Constants to indicate whether a <code>SyncProvider</code> object can
* perform updates to an SQL <code>VIEW</code> <BR>
* These constants are explained in the preceding section (4.0).
* <UL>
* <LI>SyncProvider.UPDATABLE_VIEW_SYNC
* <LI>SyncProvider.NONUPDATABLE_VIEW_SYNC
* </UL>
* </OL>
*
* @author Jonathan Bruce
* @see javax.sql.rowset.spi.SyncFactory
* @see javax.sql.rowset.spi.SyncFactoryException
*/
public abstract class SyncProvider {
/**
* Creates a default <code>SyncProvider</code> object.
*/
public SyncProvider() {
}
/**
* Returns the unique identifier for this <code>SyncProvider</code> object.
*
* @return a <code>String</code> object with the fully qualified class name of
* this <code>SyncProvider</code> object
*/
public abstract String getProviderID();
/**
* Returns a <code>javax.sql.RowSetReader</code> object, which can be used to
* populate a <code>RowSet</code> object with data.
*
* @return a <code>javax.sql.RowSetReader</code> object
*/
public abstract RowSetReader getRowSetReader();
/**
* Returns a <code>javax.sql.RowSetWriter</code> object, which can be
* used to write a <code>RowSet</code> object's data back to the
* underlying data source.
*
* @return a <code>javax.sql.RowSetWriter</code> object
*/
public abstract RowSetWriter getRowSetWriter();
/**
* Returns a constant indicating the
* grade of synchronization a <code>RowSet</code> object can expect from
* this <code>SyncProvider</code> object.
*
* @return an int that is one of the following constants:
* SyncProvider.GRADE_NONE,
* SyncProvider.GRADE_CHECK_MODIFIED_AT_COMMIT,
* SyncProvider.GRADE_CHECK_ALL_AT_COMMIT,
* SyncProvider.GRADE_LOCK_WHEN_MODIFIED,
* SyncProvider.GRADE_LOCK_WHEN_LOADED
*/
public abstract int getProviderGrade();
/**
* Sets a lock on the underlying data source at the level indicated by
* <i>datasource_lock</i>. This should cause the
* <code>SyncProvider</code> to adjust its behavior by increasing or
* decreasing the level of optimism it provides for a successful
* synchronization.
*
* @param datasource_lock one of the following constants indicating the severity
* level of data source lock required:
* <pre>
* SyncProvider.DATASOURCE_NO_LOCK,
* SyncProvider.DATASOURCE_ROW_LOCK,
* SyncProvider.DATASOURCE_TABLE_LOCK,
* SyncProvider.DATASOURCE_DB_LOCK,
* </pre>
* @throws SyncProviderException if an unsupported data source locking level
* is set.
* @see #getDataSourceLock
*/
public abstract void setDataSourceLock(int datasource_lock)
throws SyncProviderException;
/**
* Returns the current data source lock severity level active in this
* <code>SyncProvider</code> implementation.
*
* @return a constant indicating the current level of data source lock
* active in this <code>SyncProvider</code> object;
* one of the following:
* <pre>
* SyncProvider.DATASOURCE_NO_LOCK,
* SyncProvider.DATASOURCE_ROW_LOCK,
* SyncProvider.DATASOURCE_TABLE_LOCK,
* SyncProvider.DATASOURCE_DB_LOCK
* </pre>
* @throws SyncProviderException if an error occurs determining the data
* source locking level.
* @see #setDataSourceLock
*/
public abstract int getDataSourceLock()
throws SyncProviderException;
/**
* Returns whether this <code>SyncProvider</code> implementation
* can perform synchronization between a <code>RowSet</code> object
* and the SQL <code>VIEW</code> in the data source from which
* the <code>RowSet</code> object got its data.
*
* @return an <code>int</code> saying whether this <code>SyncProvider</code>
* object supports updating an SQL <code>VIEW</code>; one of the
* following:
* SyncProvider.UPDATABLE_VIEW_SYNC,
* SyncProvider.NONUPDATABLE_VIEW_SYNC
*/
public abstract int supportsUpdatableView();
/**
* Returns the release version of this <code>SyncProvider</code> instance.
*
* @return a <code>String</code> detailing the release version of the
* <code>SyncProvider</code> implementation
*/
public abstract String getVersion();
/**
* Returns the vendor name of this <code>SyncProvider</code> instance
*
* @return a <code>String</code> detailing the vendor name of this
* <code>SyncProvider</code> implementation
*/
public abstract String getVendor();
/*
* Standard description of synchronization grades that a SyncProvider
* could provide.
*/
/**
* Indicates that no synchronization with the originating data source is
* provided. A <code>SyncProvider</code>
* implementation returning this grade will simply attempt to write
* updates in the <code>RowSet</code> object to the underlying data
* source without checking the validity of any data.
*
*/
public static final int GRADE_NONE = 1;
/**
* Indicates a low level optimistic synchronization grade with
* respect to the originating data source.
*
* A <code>SyncProvider</code> implementation
* returning this grade will check only rows that have changed.
*
*/
public static final int GRADE_CHECK_MODIFIED_AT_COMMIT = 2;
/**
* Indicates a high level optimistic synchronization grade with
* respect to the originating data source.
*
* A <code>SyncProvider</code> implementation
* returning this grade will check all rows, including rows that have not
* changed.
*/
public static final int GRADE_CHECK_ALL_AT_COMMIT = 3;
/**
* Indicates a pessimistic synchronization grade with
* respect to the originating data source.
*
* A <code>SyncProvider</code>
* implementation returning this grade will lock the row in the originating
* data source.
*/
public static final int GRADE_LOCK_WHEN_MODIFIED = 4;
/**
* Indicates the most pessimistic synchronization grade with
* respect to the originating
* data source. A <code>SyncProvider</code>
* implementation returning this grade will lock the entire view and/or
* table affected by the original statement used to populate a
* <code>RowSet</code> object.
*/
public static final int GRADE_LOCK_WHEN_LOADED = 5;
/**
* Indicates that no locks remain on the originating data source. This is the default
* lock setting for all <code>SyncProvider</code> implementations unless
* otherwise directed by a <code>RowSet</code> object.
*/
public static final int DATASOURCE_NO_LOCK = 1;
/**
* Indicates that a lock is placed on the rows that are touched by the original
* SQL statement used to populate the <code>RowSet</code> object
* that is using this <code>SyncProvider</code> object.
*/
public static final int DATASOURCE_ROW_LOCK = 2;
/**
* Indicates that a lock is placed on all tables that are touched by the original
* SQL statement used to populate the <code>RowSet</code> object
* that is using this <code>SyncProvider</code> object.
*/
public static final int DATASOURCE_TABLE_LOCK = 3;
/**
* Indicates that a lock is placed on the entire data source that is the source of
* data for the <code>RowSet</code> object
* that is using this <code>SyncProvider</code> object.
*/
public static final int DATASOURCE_DB_LOCK = 4;
/**
* Indicates that a <code>SyncProvider</code> implementation
* supports synchronization between a <code>RowSet</code> object and
* the SQL <code>VIEW</code> used to populate it.
*/
public static final int UPDATABLE_VIEW_SYNC = 5;
/**
* Indicates that a <code>SyncProvider</code> implementation
* does <B>not</B> support synchronization between a <code>RowSet</code>
* object and the SQL <code>VIEW</code> used to populate it.
*/
public static final int NONUPDATABLE_VIEW_SYNC = 6;
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.spi;
import java.sql.SQLException;
import javax.sql.rowset.*;
/**
* Indicates an error with the <code>SyncProvider</code> mechanism. This exception
* is created by a <code>SyncProvider</code> abstract class extension if it
* encounters violations in reading from or writing to the originating data source.
* <P>
* If it is implemented to do so, the <code>SyncProvider</code> object may also create a
* <code>SyncResolver</code> object and either initialize the <code>SyncProviderException</code>
* object with it at construction time or set it with the <code>SyncProvider</code> object at
* a later time.
* <P>
* The method <code>acceptChanges</code> will throw this exception after the writer
* has finished checking for conflicts and has found one or more conflicts. An
* application may catch a <code>SyncProviderException</code> object and call its
* <code>getSyncResolver</code> method to get its <code>SyncResolver</code> object.
* See the code fragment in the interface comment for
* <a href="SyncResolver.html"><code>SyncResolver</code></a> for an example.
* This <code>SyncResolver</code> object will mirror the <code>RowSet</code>
* object that generated the exception, except that it will contain only the values
* from the data source that are in conflict. All other values in the <code>SyncResolver</code>
* object will be <code>null</code>.
* <P>
* The <code>SyncResolver</code> object may be used to examine and resolve
* each conflict in a row and then go to the next row with a conflict to
* repeat the procedure.
* <P>
* A <code>SyncProviderException</code> object may or may not contain a description of the
* condition causing the exception. The inherited method <code>getMessage</code> may be
* called to retrieve the description if there is one.
*
* @author Jonathan Bruce
* @see javax.sql.rowset.spi.SyncFactory
* @see javax.sql.rowset.spi.SyncResolver
* @see javax.sql.rowset.spi.SyncFactoryException
*/
public class SyncProviderException extends java.sql.SQLException {
/**
* The instance of <code>javax.sql.rowset.spi.SyncResolver</code> that
* this <code>SyncProviderException</code> object will return when its
* <code>getSyncResolver</code> method is called.
*/
private SyncResolver syncResolver = null;
/**
* Creates a new <code>SyncProviderException</code> object without a detail message.
*/
public SyncProviderException() {
super();
}
/**
* Constructs a <code>SyncProviderException</code> object with the specified
* detail message.
*
* @param msg the detail message
*/
public SyncProviderException(String msg) {
super(msg);
}
/**
* Constructs a <code>SyncProviderException</code> object with the specified
* <code>SyncResolver</code> instance.
*
* @param syncResolver the <code>SyncResolver</code> instance used to
* to process the synchronization conflicts
* @throws IllegalArgumentException if the <code>SyncResolver</code> object
* is <code>null</code>.
*/
public SyncProviderException(SyncResolver syncResolver) {
if (syncResolver == null) {
throw new IllegalArgumentException("Cannot instantiate a SyncProviderException " +
"with a null SyncResolver object");
} else {
this.syncResolver = syncResolver;
}
}
/**
* Retrieves the <code>SyncResolver</code> object that has been set for
* this <code>SyncProviderException</code> object, or
* if none has been set, an instance of the default <code>SyncResolver</code>
* implementation included in the reference implementation.
* <P>
* If a <code>SyncProviderException</code> object is thrown, an application
* may use this method to generate a <code>SyncResolver</code> object
* with which to resolve the conflict or conflicts that caused the
* exception to be thrown.
*
* @return the <code>SyncResolver</code> object set for this
* <code>SyncProviderException</code> object or, if none has
* been set, an instance of the default <code>SyncResolver</code>
* implementation. In addition, the default <code>SyncResolver</code>
* implementation is also returned if the <code>SyncResolver()</code> or
* <code>SyncResolver(String)</code> constructors are used to instantiate
* the <code>SyncResolver</code> instance.
*/
public SyncResolver getSyncResolver() {
if (syncResolver != null) {
return syncResolver;
} else {
try {
syncResolver = new com.sun.rowset.internal.SyncResolverImpl();
} catch (SQLException sqle) {
}
return syncResolver;
}
}
/**
* Sets the <code>SyncResolver</code> object for this
* <code>SyncProviderException</code> object to the one supplied.
* If the argument supplied is <code>null</code>, a call to the method
* <code>getSyncResolver</code> will return the default reference
* implementation of the <code>SyncResolver</code> interface.
*
* @param syncResolver the <code>SyncResolver</code> object to be set;
* cannot be <code>null</code>
* @throws IllegalArgumentException if the <code>SyncResolver</code> object
* is <code>null</code>.
* @see #getSyncResolver
*/
public void setSyncResolver(SyncResolver syncResolver) {
if (syncResolver == null) {
throw new IllegalArgumentException("Cannot set a null SyncResolver " +
"object");
} else {
this.syncResolver = syncResolver;
}
}
static final long serialVersionUID = -939908523620640692L;
}

View File

@@ -0,0 +1,375 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.spi;
import javax.sql.RowSet;
import java.sql.SQLException;
/**
* Defines a framework that allows applications to use a manual decision tree
* to decide what should be done when a synchronization conflict occurs.
* Although it is not mandatory for
* applications to resolve synchronization conflicts manually, this
* framework provides the means to delegate to the application when conflicts
* arise.
* <p>
* Note that a conflict is a situation where the <code>RowSet</code> object's original
* values for a row do not match the values in the data source, which indicates that
* the data source row has been modified since the last synchronization. Note also that
* a <code>RowSet</code> object's original values are the values it had just prior to the
* the last synchronization, which are not necessarily its initial values.
*
*
* <H2>Description of a <code>SyncResolver</code> Object</H2>
*
* A <code>SyncResolver</code> object is a specialized <code>RowSet</code> object
* that implements the <code>SyncResolver</code> interface.
* It <b>may</b> operate as either a connected <code>RowSet</code> object (an
* implementation of the <code>JdbcRowSet</code> interface) or a connected
* <code>RowSet</code> object (an implementation of the
* <code>CachedRowSet</code> interface or one of its subinterfaces). For information
* on the subinterfaces, see the
* <a href="../package-summary.html"><code>javax.sql.rowset</code></a> package
* description. The reference implementation for <code>SyncResolver</code> implements
* the <code>CachedRowSet</code> interface, but other implementations
* may choose to implement the <code>JdbcRowSet</code> interface to satisfy
* particular needs.
* <P>
* After an application has attempted to synchronize a <code>RowSet</code> object with
* the data source (by calling the <code>CachedRowSet</code>
* method <code>acceptChanges</code>), and one or more conflicts have been found,
* a rowset's <code>SyncProvider</code> object creates an instance of
* <code>SyncResolver</code>. This new <code>SyncResolver</code> object has
* the same number of rows and columns as the
* <code>RowSet</code> object that was attempting the synchronization. The
* <code>SyncResolver</code> object contains the values from the data source that caused
* the conflict(s) and <code>null</code> for all other values.
* In addition, it contains information about each conflict.
*
*
* <H2>Getting and Using a <code>SyncResolver</code> Object</H2>
*
* When the method <code>acceptChanges</code> encounters conflicts, the
* <code>SyncProvider</code> object creates a <code>SyncProviderException</code>
* object and sets it with the new <code>SyncResolver</code> object. The method
* <code>acceptChanges</code> will throw this exception, which
* the application can then catch and use to retrieve the
* <code>SyncResolver</code> object it contains. The following code snippet uses the
* <code>SyncProviderException</code> method <code>getSyncResolver</code> to get
* the <code>SyncResolver</code> object <i>resolver</i>.
* <PRE>
* {@code
* } catch (SyncProviderException spe) {
* SyncResolver resolver = spe.getSyncResolver();
* ...
* }
*
* }
* </PRE>
* <P>
* With <i>resolver</i> in hand, an application can use it to get the information
* it contains about the conflict or conflicts. A <code>SyncResolver</code> object
* such as <i>resolver</i> keeps
* track of the conflicts for each row in which there is a conflict. It also places a
* lock on the table or tables affected by the rowset's command so that no more
* conflicts can occur while the current conflicts are being resolved.
* <P>
* The following kinds of information can be obtained from a <code>SyncResolver</code>
* object:
*
* <h3>What operation was being attempted when a conflict occurred</h3>
* The <code>SyncProvider</code> interface defines four constants
* describing states that may occur. Three
* constants describe the type of operation (update, delete, or insert) that a
* <code>RowSet</code> object was attempting to perform when a conflict was discovered,
* and the fourth indicates that there is no conflict.
* These constants are the possible return values when a <code>SyncResolver</code> object
* calls the method <code>getStatus</code>.
* <PRE>
* {@code int operation = resolver.getStatus(); }
* </PRE>
*
* <h3>The value in the data source that caused a conflict</h3>
* A conflict exists when a value that a <code>RowSet</code> object has changed
* and is attempting to write to the data source
* has also been changed in the data source since the last synchronization. An
* application can call the <code>SyncResolver</code> method
* <code>getConflictValue</code > to retrieve the
* value in the data source that is the cause of the conflict because the values in a
* <code>SyncResolver</code> object are the conflict values from the data source.
* <PRE>
* java.lang.Object conflictValue = resolver.getConflictValue(2);
* </PRE>
* Note that the column in <i>resolver</i> can be designated by the column number,
* as is done in the preceding line of code, or by the column name.
* <P>
* With the information retrieved from the methods <code>getStatus</code> and
* <code>getConflictValue</code>, the application may make a determination as to
* which value should be persisted in the data source. The application then calls the
* <code>SyncResolver</code> method <code>setResolvedValue</code>, which sets the value
* to be persisted in the <code>RowSet</code> object and also in the data source.
* <PRE>
* resolver.setResolvedValue("DEPT", 8390426);
* </PRE>
* In the preceding line of code,
* the column name designates the column in the <code>RowSet</code> object
* that is to be set with the given value. The column number can also be used to
* designate the column.
* <P>
* An application calls the method <code>setResolvedValue</code> after it has
* resolved all of the conflicts in the current conflict row and repeats this process
* for each conflict row in the <code>SyncResolver</code> object.
*
*
* <H2>Navigating a <code>SyncResolver</code> Object</H2>
*
* Because a <code>SyncResolver</code> object is a <code>RowSet</code> object, an
* application can use all of the <code>RowSet</code> methods for moving the cursor
* to navigate a <code>SyncResolver</code> object. For example, an application can
* use the <code>RowSet</code> method <code>next</code> to get to each row and then
* call the <code>SyncResolver</code> method <code>getStatus</code> to see if the row
* contains a conflict. In a row with one or more conflicts, the application can
* iterate through the columns to find any non-null values, which will be the values
* from the data source that are in conflict.
* <P>
* To make it easier to navigate a <code>SyncResolver</code> object, especially when
* there are large numbers of rows with no conflicts, the <code>SyncResolver</code>
* interface defines the methods <code>nextConflict</code> and
* <code>previousConflict</code>, which move only to rows
* that contain at least one conflict value. Then an application can call the
* <code>SyncResolver</code> method <code>getConflictValue</code>, supplying it
* with the column number, to get the conflict value itself. The code fragment in the
* next section gives an example.
*
* <H2>Code Example</H2>
*
* The following code fragment demonstrates how a disconnected <code>RowSet</code>
* object <i>crs</i> might attempt to synchronize itself with the
* underlying data source and then resolve the conflicts. In the <code>try</code>
* block, <i>crs</i> calls the method <code>acceptChanges</code>, passing it the
* <code>Connection</code> object <i>con</i>. If there are no conflicts, the
* changes in <i>crs</i> are simply written to the data source. However, if there
* is a conflict, the method <code>acceptChanges</code> throws a
* <code>SyncProviderException</code> object, and the
* <code>catch</code> block takes effect. In this example, which
* illustrates one of the many ways a <code>SyncResolver</code> object can be used,
* the <code>SyncResolver</code> method <code>nextConflict</code> is used in a
* <code>while</code> loop. The loop will end when <code>nextConflict</code> returns
* <code>false</code>, which will occur when there are no more conflict rows in the
* <code>SyncResolver</code> object <i>resolver</i>. In This particular code fragment,
* <i>resolver</i> looks for rows that have update conflicts (rows with the status
* <code>SyncResolver.UPDATE_ROW_CONFLICT</code>), and the rest of this code fragment
* executes only for rows where conflicts occurred because <i>crs</i> was attempting an
* update.
* <P>
* After the cursor for <i>resolver</i> has moved to the next conflict row that
* has an update conflict, the method <code>getRow</code> indicates the number of the
* current row, and
* the cursor for the <code>CachedRowSet</code> object <i>crs</i> is moved to
* the comparable row in <i>crs</i>. By iterating
* through the columns of that row in both <i>resolver</i> and <i>crs</i>, the conflicting
* values can be retrieved and compared to decide which one should be persisted. In this
* code fragment, the value in <i>crs</i> is the one set as the resolved value, which means
* that it will be used to overwrite the conflict value in the data source.
*
* <PRE>
* {@code
* try {
*
* crs.acceptChanges(con);
*
* } catch (SyncProviderException spe) {
*
* SyncResolver resolver = spe.getSyncResolver();
*
* Object crsValue; // value in the RowSet object
* Object resolverValue: // value in the SyncResolver object
* Object resolvedValue: // value to be persisted
*
* while(resolver.nextConflict()) {
* if(resolver.getStatus() == SyncResolver.UPDATE_ROW_CONFLICT) {
* int row = resolver.getRow();
* crs.absolute(row);
*
* int colCount = crs.getMetaData().getColumnCount();
* for(int j = 1; j <= colCount; j++) {
* if (resolver.getConflictValue(j) != null) {
* crsValue = crs.getObject(j);
* resolverValue = resolver.getConflictValue(j);
* . . .
* // compare crsValue and resolverValue to determine
* // which should be the resolved value (the value to persist)
* resolvedValue = crsValue;
*
* resolver.setResolvedValue(j, resolvedValue);
* }
* }
* }
* }
* }
* }</PRE>
* @author Jonathan Bruce
*/
public interface SyncResolver extends RowSet {
/**
* Indicates that a conflict occurred while the <code>RowSet</code> object was
* attempting to update a row in the data source.
* The values in the data source row to be updated differ from the
* <code>RowSet</code> object's original values for that row, which means that
* the row in the data source has been updated or deleted since the last
* synchronization.
*/
public static int UPDATE_ROW_CONFLICT = 0;
/**
* Indicates that a conflict occurred while the <code>RowSet</code> object was
* attempting to delete a row in the data source.
* The values in the data source row to be updated differ from the
* <code>RowSet</code> object's original values for that row, which means that
* the row in the data source has been updated or deleted since the last
* synchronization.
*/
public static int DELETE_ROW_CONFLICT = 1;
/**
* Indicates that a conflict occurred while the <code>RowSet</code> object was
* attempting to insert a row into the data source. This means that a
* row with the same primary key as the row to be inserted has been inserted
* into the data source since the last synchronization.
*/
public static int INSERT_ROW_CONFLICT = 2;
/**
* Indicates that <b>no</b> conflict occurred while the <code>RowSet</code> object
* was attempting to update, delete or insert a row in the data source. The values in
* the <code>SyncResolver</code> will contain <code>null</code> values only as an indication
* that no information in pertinent to the conflict resolution in this row.
*/
public static int NO_ROW_CONFLICT = 3;
/**
* Retrieves the conflict status of the current row of this <code>SyncResolver</code>,
* which indicates the operation
* the <code>RowSet</code> object was attempting when the conflict occurred.
*
* @return one of the following constants:
* <code>SyncResolver.UPDATE_ROW_CONFLICT</code>,
* <code>SyncResolver.DELETE_ROW_CONFLICT</code>,
* <code>SyncResolver.INSERT_ROW_CONFLICT</code>, or
* <code>SyncResolver.NO_ROW_CONFLICT</code>
*/
public int getStatus();
/**
* Retrieves the value in the designated column in the current row of this
* <code>SyncResolver</code> object, which is the value in the data source
* that caused a conflict.
*
* @param index an <code>int</code> designating the column in this row of this
* <code>SyncResolver</code> object from which to retrieve the value
* causing a conflict
* @return the value of the designated column in the current row of this
* <code>SyncResolver</code> object
* @throws SQLException if a database access error occurs
*/
public Object getConflictValue(int index) throws SQLException;
/**
* Retrieves the value in the designated column in the current row of this
* <code>SyncResolver</code> object, which is the value in the data source
* that caused a conflict.
*
* @param columnName a <code>String</code> object designating the column in this row of this
* <code>SyncResolver</code> object from which to retrieve the value
* causing a conflict
* @return the value of the designated column in the current row of this
* <code>SyncResolver</code> object
* @throws SQLException if a database access error occurs
*/
public Object getConflictValue(String columnName) throws SQLException;
/**
* Sets <i>obj</i> as the value in column <i>index</i> in the current row of the
* <code>RowSet</code> object that is being synchronized. <i>obj</i>
* is set as the value in the data source internally.
*
* @param index an <code>int</code> giving the number of the column into which to
* set the value to be persisted
* @param obj an <code>Object</code> that is the value to be set in the
* <code>RowSet</code> object and persisted in the data source
* @throws SQLException if a database access error occurs
*/
public void setResolvedValue(int index, Object obj) throws SQLException;
/**
* Sets <i>obj</i> as the value in column <i>columnName</i> in the current row of the
* <code>RowSet</code> object that is being synchronized. <i>obj</i>
* is set as the value in the data source internally.
*
* @param columnName a <code>String</code> object giving the name of the column
* into which to set the value to be persisted
* @param obj an <code>Object</code> that is the value to be set in the
* <code>RowSet</code> object and persisted in the data source
* @throws SQLException if a database access error occurs
*/
public void setResolvedValue(String columnName, Object obj) throws SQLException;
/**
* Moves the cursor down from its current position to the next row that contains
* a conflict value. A <code>SyncResolver</code> object's
* cursor is initially positioned before the first conflict row; the first call to the
* method <code>nextConflict</code> makes the first conflict row the current row;
* the second call makes the second conflict row the current row, and so on.
* <p>
* A call to the method <code>nextConflict</code> will implicitly close
* an input stream if one is open and will clear the <code>SyncResolver</code>
* object's warning chain.
*
* @return <code>true</code> if the new current row is valid; <code>false</code>
* if there are no more rows
* @throws SQLException if a database access error occurs or the result set type
* is <code>TYPE_FORWARD_ONLY</code>
*
*/
public boolean nextConflict() throws SQLException;
/**
* Moves the cursor up from its current position to the previous conflict
* row in this <code>SyncResolver</code> object.
* <p>
* A call to the method <code>previousConflict</code> will implicitly close
* an input stream if one is open and will clear the <code>SyncResolver</code>
* object's warning chain.
*
* @return <code>true</code> if the cursor is on a valid row; <code>false</code>
* if it is off the result set
* @throws SQLException if a database access error occurs or the result set type
* is <code>TYPE_FORWARD_ONLY</code>
*/
public boolean previousConflict() throws SQLException;
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.spi;
import java.sql.SQLException;
import java.io.Reader;
import javax.sql.RowSetWriter;
import javax.sql.rowset.*;
import java.sql.Savepoint;
/**
* A specialized interface that facilitates an extension of the standard
* <code>SyncProvider</code> abstract class so that it has finer grained
* transaction control.
* <p>
* If one or more disconnected <code>RowSet</code> objects are participating
* in a global transaction, they may wish to coordinate their synchronization
* commits to preserve data integrity and reduce the number of
* synchronization exceptions. If this is the case, an application should set
* the <code>CachedRowSet</code> constant <code>COMMIT_ON_ACCEPT_CHANGES</code>
* to <code>false</code> and use the <code>commit</code> and <code>rollback</code>
* methods defined in this interface to manage transaction boundaries.
*/
public interface TransactionalWriter extends RowSetWriter {
/**
* Makes permanent all changes that have been performed by the
* <code>acceptChanges</code> method since the last call to either the
* <code>commit</code> or <code>rollback</code> methods.
* This method should be used only when auto-commit mode has been disabled.
*
* @throws SQLException if a database access error occurs or the
* <code>Connection</code> object within this <code>CachedRowSet</code>
* object is in auto-commit mode
*/
public void commit() throws SQLException;
/**
* Undoes all changes made in the current transaction. This method should be
* used only when auto-commit mode has been disabled.
*
* @throws SQLException if a database access error occurs or the <code>Connection</code>
* object within this <code>CachedRowSet</code> object is in auto-commit mode
*/
public void rollback() throws SQLException;
/**
* Undoes all changes made in the current transaction made prior to the given
* <code>Savepoint</code> object. This method should be used only when auto-commit
* mode has been disabled.
*
* @param s a <code>Savepoint</code> object marking a savepoint in the current
* transaction. All changes made before <i>s</i> was set will be undone.
* All changes made after <i>s</i> was set will be made permanent.
* @throws SQLException if a database access error occurs or the <code>Connection</code>
* object within this <code>CachedRowSet</code> object is in auto-commit mode
*/
public void rollback(Savepoint s) throws SQLException;
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.spi;
import java.sql.SQLException;
import java.io.Reader;
import javax.sql.RowSetReader;
import javax.sql.rowset.*;
/**
* A specialized interface that facilitates an extension of the
* <code>SyncProvider</code> abstract class for XML orientated
* synchronization providers.
* <P>
* <code>SyncProvider</code> implementations that supply XML data reader
* capabilities such as output XML stream capabilities can implement this
* interface to provide standard <code>XmlReader</code> objects to
* <code>WebRowSet</code> implementations.
* <p>
* An <code>XmlReader</code> object is registered as the
* XML reader for a <code>WebRowSet</code> by being assigned to the
* rowset's <code>xmlReader</code> field. When the <code>WebRowSet</code>
* object's <code>readXml</code> method is invoked, it in turn invokes
* its XML reader's <code>readXML</code> method.
*/
public interface XmlReader extends RowSetReader {
/**
* Reads and parses the given <code>WebRowSet</code> object from the given
* input stream in XML format. The <code>xmlReader</code> field of the
* given <code>WebRowSet</code> object must contain this
* <code>XmlReader</code> object.
* <P>
* If a parsing error occurs, the exception that is thrown will
* include information about the location of the error in the
* original XML document.
*
* @param caller the <code>WebRowSet</code> object to be parsed, whose
* <code>xmlReader</code> field must contain a reference to
* this <code>XmlReader</code> object
* @param reader the <code>java.io.Reader</code> object from which
* <code>caller</code> will be read
* @throws SQLException if a database access error occurs or
* this <code>XmlReader</code> object is not the reader
* for the given rowset
*/
public void readXML(WebRowSet caller, java.io.Reader reader)
throws SQLException;
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.sql.rowset.spi;
import java.sql.SQLException;
import java.io.Writer;
import javax.sql.RowSetWriter;
import javax.sql.rowset.*;
/**
* A specialized interface that facilitates an extension of the
* <code>SyncProvider</code> abstract class for XML orientated
* synchronization providers.
* <p>
* <code>SyncProvider</code> implementations that supply XML data writer
* capabilities such as output XML stream capabilities can implement this
* interface to provide standard <code>XmlWriter</code> objects to
* <code>WebRowSet</code> implementations.
* <P>
* Writing a <code>WebRowSet</code> object includes printing the
* rowset's data, metadata, and properties, all with the
* appropriate XML tags.
*/
public interface XmlWriter extends RowSetWriter {
/**
* Writes the given <code>WebRowSet</code> object to the specified
* <code>java.io.Writer</code> output stream as an XML document.
* This document includes the rowset's data, metadata, and properties
* plus the appropriate XML tags.
* <P>
* The <code>caller</code> parameter must be a <code>WebRowSet</code>
* object whose <code>XmlWriter</code> field contains a reference to
* this <code>XmlWriter</code> object.
*
* @param caller the <code>WebRowSet</code> instance to be written,
* for which this <code>XmlWriter</code> object is the writer
* @param writer the <code>java.io.Writer</code> object that serves
* as the output stream for writing <code>caller</code> as
* an XML document
* @throws SQLException if a database access error occurs or
* this <code>XmlWriter</code> object is not the writer
* for the given <code>WebRowSet</code> object
*/
public void writeXML(WebRowSet caller, java.io.Writer writer)
throws SQLException;
}