Interface that defines the methods which are common between DataSource, XADataSource and ConnectionPoolDataSource.
Interface that defines the methods which are common between DataSource, XADataSource and ConnectionPoolDataSource.
An Event object that provides information about the source of a connection-related event. ConnectionEvent objects are generated when an application closes a pooled connection and when an error occurs. The ConnectionEvent object contains two kinds of information:
The pooled connection closed by the application In the case of an error event, the SQLException about to be thrown to the application
An Event object that provides information about the source of a connection-related event. ConnectionEvent objects are generated when an application closes a pooled connection and when an error occurs. The ConnectionEvent object contains two kinds of information: The pooled connection closed by the application In the case of an error event, the SQLException about to be thrown to the application
An object that registers to be notified of events generated by a PooledConnection object.
The ConnectionEventListener interface is implemented by a connection pooling component. A connection pooling component will usually be provided by a JDBC driver vendor or another system software vendor. A JDBC driver notifies a ConnectionEventListener object when an application is finished using a pooled connection with which the listener has registered. The notification occurs after the application calls the method close on its representation of a PooledConnection object. A ConnectionEventListener is also notified when a connection error occurs due to the fact that the PooledConnection is unfit for future use---the server has crashed, for example. The listener is notified by the JDBC driver just before the driver throws an SQLException to the application using the PooledConnection object.
An object that registers to be notified of events generated by a PooledConnection object. The ConnectionEventListener interface is implemented by a connection pooling component. A connection pooling component will usually be provided by a JDBC driver vendor or another system software vendor. A JDBC driver notifies a ConnectionEventListener object when an application is finished using a pooled connection with which the listener has registered. The notification occurs after the application calls the method close on its representation of a PooledConnection object. A ConnectionEventListener is also notified when a connection error occurs due to the fact that the PooledConnection is unfit for future use---the server has crashed, for example. The listener is notified by the JDBC driver just before the driver throws an SQLException to the application using the PooledConnection object.
A factory for PooledConnection objects. An object that implements this interface will typically be registered with a naming service that is based on the Java™ Naming and Directory Interface (JNDI).
A factory for PooledConnection objects. An object that implements this interface will typically be registered with a naming service that is based on the Java™ Naming and Directory Interface (JNDI).
No vars found in this namespace.
A factory for connections to the physical data source that this DataSource object represents. An alternative to the DriverManager facility, a DataSource object is the preferred means of getting a connection. An object that implements the DataSource interface will typically be registered with a naming service based on the Java™ Naming and Directory (JNDI) API.
The DataSource interface is implemented by a driver vendor. There are three types of implementations:
Basic implementation -- produces a standard Connection object Connection pooling implementation -- produces a Connection object that will automatically participate in connection pooling. This implementation works with a middle-tier connection pooling manager. Distributed transaction implementation -- produces a Connection object that may be used for distributed transactions and almost always participates in connection pooling. This implementation works with a middle-tier transaction manager and almost always with a connection pooling manager.
A DataSource object has properties that can be modified when necessary. For example, if the data source is moved to a different server, the property for the server can be changed. The benefit is that because the data source's properties can be changed, any code accessing that data source does not need to be changed.
A driver that is accessed via a DataSource object does not register itself with the DriverManager. Rather, a DataSource object is retrieved though a lookup operation and then used to create a Connection object. With a basic implementation, the connection obtained through a DataSource object is identical to a connection obtained through the DriverManager facility.
An implementation of DataSource must include a public no-arg constructor.
A factory for connections to the physical data source that this DataSource object represents. An alternative to the DriverManager facility, a DataSource object is the preferred means of getting a connection. An object that implements the DataSource interface will typically be registered with a naming service based on the Java™ Naming and Directory (JNDI) API. The DataSource interface is implemented by a driver vendor. There are three types of implementations: Basic implementation -- produces a standard Connection object Connection pooling implementation -- produces a Connection object that will automatically participate in connection pooling. This implementation works with a middle-tier connection pooling manager. Distributed transaction implementation -- produces a Connection object that may be used for distributed transactions and almost always participates in connection pooling. This implementation works with a middle-tier transaction manager and almost always with a connection pooling manager. A DataSource object has properties that can be modified when necessary. For example, if the data source is moved to a different server, the property for the server can be changed. The benefit is that because the data source's properties can be changed, any code accessing that data source does not need to be changed. A driver that is accessed via a DataSource object does not register itself with the DriverManager. Rather, a DataSource object is retrieved though a lookup operation and then used to create a Connection object. With a basic implementation, the connection obtained through a DataSource object is identical to a connection obtained through the DriverManager facility. An implementation of DataSource must include a public no-arg constructor.
An object that provides hooks for connection pool management. A PooledConnection object represents a physical connection to a data source. The connection can be recycled rather than being closed when an application is finished with it, thus reducing the number of connections that need to be made.
An application programmer does not use the PooledConnection interface directly; rather, it is used by a middle tier infrastructure that manages the pooling of connections.
When an application calls the method DataSource.getConnection, it gets back a Connection object. If connection pooling is being done, that Connection object is actually a handle to a PooledConnection object, which is a physical connection.
The connection pool manager, typically the application server, maintains a pool of PooledConnection objects. If there is a PooledConnection object available in the pool, the connection pool manager returns a Connection object that is a handle to that physical connection. If no PooledConnection object is available, the connection pool manager calls the ConnectionPoolDataSource method getPoolConnection to create a new physical connection. The JDBC driver implementing ConnectionPoolDataSource creates a new PooledConnection object and returns a handle to it.
When an application closes a connection, it calls the Connection method close. When connection pooling is being done, the connection pool manager is notified because it has registered itself as a ConnectionEventListener object using the ConnectionPool method addConnectionEventListener. The connection pool manager deactivates the handle to the PooledConnection object and returns the PooledConnection object to the pool of connections so that it can be used again. Thus, when an application closes its connection, the underlying physical connection is recycled rather than being closed.
The physical connection is not closed until the connection pool manager calls the PooledConnection method close. This method is generally called to have an orderly shutdown of the server or if a fatal error has made the connection unusable.
A connection pool manager is often also a statement pool manager, maintaining a pool of PreparedStatement objects. When an application closes a prepared statement, it calls the PreparedStatement method close. When Statement pooling is being done, the pool manager is notified because it has registered itself as a StatementEventListener object using the ConnectionPool method addStatementEventListener. Thus, when an application closes its PreparedStatement, the underlying prepared statement is recycled rather than being closed.
An object that provides hooks for connection pool management. A PooledConnection object represents a physical connection to a data source. The connection can be recycled rather than being closed when an application is finished with it, thus reducing the number of connections that need to be made. An application programmer does not use the PooledConnection interface directly; rather, it is used by a middle tier infrastructure that manages the pooling of connections. When an application calls the method DataSource.getConnection, it gets back a Connection object. If connection pooling is being done, that Connection object is actually a handle to a PooledConnection object, which is a physical connection. The connection pool manager, typically the application server, maintains a pool of PooledConnection objects. If there is a PooledConnection object available in the pool, the connection pool manager returns a Connection object that is a handle to that physical connection. If no PooledConnection object is available, the connection pool manager calls the ConnectionPoolDataSource method getPoolConnection to create a new physical connection. The JDBC driver implementing ConnectionPoolDataSource creates a new PooledConnection object and returns a handle to it. When an application closes a connection, it calls the Connection method close. When connection pooling is being done, the connection pool manager is notified because it has registered itself as a ConnectionEventListener object using the ConnectionPool method addConnectionEventListener. The connection pool manager deactivates the handle to the PooledConnection object and returns the PooledConnection object to the pool of connections so that it can be used again. Thus, when an application closes its connection, the underlying physical connection is recycled rather than being closed. The physical connection is not closed until the connection pool manager calls the PooledConnection method close. This method is generally called to have an orderly shutdown of the server or if a fatal error has made the connection unusable. A connection pool manager is often also a statement pool manager, maintaining a pool of PreparedStatement objects. When an application closes a prepared statement, it calls the PreparedStatement method close. When Statement pooling is being done, the pool manager is notified because it has registered itself as a StatementEventListener object using the ConnectionPool method addStatementEventListener. Thus, when an application closes its PreparedStatement, the underlying prepared statement is recycled rather than being closed.
The interface that adds support to the JDBC API for the JavaBeans™ component model. A rowset, which can be used as a JavaBeans component in a visual Bean development environment, can be created and configured at design time and executed at run time.
The RowSet interface provides a set of JavaBeans properties that allow a RowSet instance to be configured to connect to a JDBC data source and read some data from the data source. A group of setter methods (setInt, setBytes, setString, and so on) provide a way to pass input parameters to a rowset's command property. This command is the SQL query the rowset uses when it gets its data from a relational database, which is generally the case.
The RowSet interface supports JavaBeans events, allowing other components in an application to be notified when an event occurs on a rowset, such as a change in its value.
The RowSet interface is unique in that it is intended to be
implemented using the rest of the JDBC API. In other words, a
RowSet implementation is a layer of software that executes on top
of a JDBC driver. Implementations of the RowSet interface can
be provided by anyone, including JDBC driver vendors who want to
provide a RowSet implementation as part of their JDBC products.
A RowSet object may make a connection with a data source and maintain that connection throughout its life cycle, in which case it is called a connected rowset. A rowset may also make a connection with a data source, get data from it, and then close the connection. Such a rowset is called a disconnected rowset. A disconnected rowset may make changes to its data while it is disconnected and then send the changes back to the original source of the data, but it must reestablish a connection to do so.
A disconnected rowset may have a reader (a RowSetReader object) and a writer (a RowSetWriter object) associated with it. The reader may be implemented in many different ways to populate a rowset with data, including getting data from a non-relational data source. The writer can also be implemented in many different ways to propagate changes made to the rowset's data back to the underlying data source.
Rowsets are easy to use. The RowSet interface extends the standard java.sql.ResultSet interface. The RowSetMetaData interface extends the java.sql.ResultSetMetaData interface. Thus, developers familiar with the JDBC API will have to learn a minimal number of new APIs to use rowsets. In addition, third-party software tools that work with JDBC ResultSet objects will also easily be made to work with rowsets.
The interface that adds support to the JDBC API for the JavaBeans™ component model. A rowset, which can be used as a JavaBeans component in a visual Bean development environment, can be created and configured at design time and executed at run time. The RowSet interface provides a set of JavaBeans properties that allow a RowSet instance to be configured to connect to a JDBC data source and read some data from the data source. A group of setter methods (setInt, setBytes, setString, and so on) provide a way to pass input parameters to a rowset's command property. This command is the SQL query the rowset uses when it gets its data from a relational database, which is generally the case. The RowSet interface supports JavaBeans events, allowing other components in an application to be notified when an event occurs on a rowset, such as a change in its value. The RowSet interface is unique in that it is intended to be implemented using the rest of the JDBC API. In other words, a RowSet implementation is a layer of software that executes `on top` of a JDBC driver. Implementations of the RowSet interface can be provided by anyone, including JDBC driver vendors who want to provide a RowSet implementation as part of their JDBC products. A RowSet object may make a connection with a data source and maintain that connection throughout its life cycle, in which case it is called a connected rowset. A rowset may also make a connection with a data source, get data from it, and then close the connection. Such a rowset is called a disconnected rowset. A disconnected rowset may make changes to its data while it is disconnected and then send the changes back to the original source of the data, but it must reestablish a connection to do so. A disconnected rowset may have a reader (a RowSetReader object) and a writer (a RowSetWriter object) associated with it. The reader may be implemented in many different ways to populate a rowset with data, including getting data from a non-relational data source. The writer can also be implemented in many different ways to propagate changes made to the rowset's data back to the underlying data source. Rowsets are easy to use. The RowSet interface extends the standard java.sql.ResultSet interface. The RowSetMetaData interface extends the java.sql.ResultSetMetaData interface. Thus, developers familiar with the JDBC API will have to learn a minimal number of new APIs to use rowsets. In addition, third-party software tools that work with JDBC ResultSet objects will also easily be made to work with rowsets.
An abstract class providing a RowSet object with its basic functionality. The basic functions include having properties and sending event notifications, which all JavaBeans™ components must implement.
1.0 Overview The BaseRowSet class provides the core functionality for all RowSet implementations, and all standard implementations may use this class in combination with one or more RowSet interfaces in order to provide a standard vendor-specific implementation. To clarify, all implementations must implement at least one of the RowSet interfaces (JdbcRowSet, CachedRowSet, JoinRowSet, FilteredRowSet, or WebRowSet). This means that any implementation that extends the BaseRowSet class must also implement one of the RowSet interfaces.
The BaseRowSet class provides the following:
Properties
Fields for storing current properties
Methods for getting and setting properties
Event notification
A complete set of setter methods for setting the parameters in a RowSet object's command
Streams
Fields for storing stream instances Constants for indicating the type of a stream
2.0 Setting Properties All rowsets maintain a set of properties, which will usually be set using a tool. The number and kinds of properties a rowset has will vary, depending on what the RowSet implementation does and how it gets its data. For example, rowsets that get their data from a ResultSet object need to set the properties that are required for making a database connection. If a RowSet object uses the DriverManager facility to make a connection, it needs to set a property for the JDBC URL that identifies the appropriate driver, and it needs to set the properties that give the user name and password. If, on the other hand, the rowset uses a DataSource object to make the connection, which is the preferred method, it does not need to set the property for the JDBC URL. Instead, it needs to set the property for the logical name of the data source along with the properties for the user name and password.
NOTE: In order to use a DataSource object for making a connection, the DataSource object must have been registered with a naming service that uses the Java Naming and Directory Interface™ (JNDI) API. This registration is usually done by a person acting in the capacity of a system administrator.
3.0 Setting the Command and Its Parameters When a rowset gets its data from a relational database, it executes a command (a query) that produces a ResultSet object. This query is the command that is set for the RowSet object's command property. The rowset populates itself with data by reading the data from the ResultSet object into itself. If the query contains placeholders for values to be set, the BaseRowSet setter methods are used to set these values. All setter methods allow these values to be set to null if required.
The following code fragment illustrates how the CachedRowSet™ object crs might have its command property set. Note that if a tool is used to set properties, this is the code that the tool would use.
crs.setCommand(SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS
WHERE CREDIT_LIMIT > ? AND REGION = ?
);
In this example, the values for CREDIT_LIMIT and REGION are placeholder parameters, which are indicated with a question mark (?). The first question mark is placeholder parameter number 1, the second question mark is placeholder parameter number 2, and so on. Any placeholder parameters must be set with values before the query can be executed. To set these placeholder parameters, the BaseRowSet class provides a set of setter methods, similar to those provided by the PreparedStatement interface, for setting values of each data type. A RowSet object stores the parameter values internally, and its execute method uses them internally to set values for the placeholder parameters before it sends the command to the DBMS to be executed.
The following code fragment demonstrates setting the two parameters in the query from the previous example.
crs.setInt(1, 5000);
crs.setString(2, West
);
If the execute method is called at this point, the query
sent to the DBMS will be:
SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS
WHERE CREDIT_LIMIT > 5000 AND REGION = 'West'
NOTE: Setting Array, Clob, Blob and
Ref objects as a command parameter, stores these values as
SerialArray, SerialClob, SerialBlob
and SerialRef objects respectively.
4.0 Handling of Parameters Behind the Scenes
NOTE: The BaseRowSet class provides two kinds of setter methods, those that set properties and those that set placeholder parameters. The setter methods discussed in this section are those that set placeholder parameters.
The placeholder parameters set with the BaseRowSet setter methods are stored as objects in an internal Hashtable object. Primitives are stored as their Object type. For example, byte is stored as Byte object, and int is stored as an Integer object. When the method execute is called, the values in the Hashtable object are substituted for the appropriate placeholder parameters in the command.
A call to the method getParams returns the values stored in the Hashtable object as an array of Object instances. An element in this array may be a simple Object instance or an array (which is a type of Object). The particular setter method used determines whether an element in this array is an Object or an array.
The majority of methods for setting placeholder parameters take two parameters, with the first parameter indicating which placeholder parameter is to be set, and the second parameter giving the value to be set. Methods such as setInt, setString, setBoolean, and setLong fall into this category. After these methods have been called, a call to the method getParams will return an array with the values that have been set. Each element in the array is an Object instance representing the values that have been set. The order of these values in the array is determined by the int (the first parameter) passed to the setter method. The values in the array are the values (the second parameter) passed to the setter method. In other words, the first element in the array is the value to be set for the first placeholder parameter in the RowSet object's command. The second element is the value to be set for the second placeholder parameter, and so on.
Several setter methods send the driver and DBMS information beyond the value to be set. When the method getParams is called after one of these setter methods has been used, the elements in the array will themselves be arrays to accommodate the additional information. In this category, the method setNull is a special case because one version takes only two parameters (setNull(int parameterIndex, int SqlType)). Nevertheless, it requires an array to contain the information that will be passed to the driver and DBMS. The first element in this array is the value to be set, which is null, and the second element is the int supplied for sqlType, which indicates the type of SQL value that is being set to null. This information is needed by some DBMSs and is therefore required in order to ensure that applications are portable. The other version is intended to be used when the value to be set to null is a user-defined type. It takes three parameters (setNull(int parameterIndex, int sqlType, String typeName)) and also requires an array to contain the information to be passed to the driver and DBMS. The first two elements in this array are the same as for the first version of setNull. The third element, typeName, gives the SQL name of the user-defined type. As is true with the other setter methods, the number of the placeholder parameter to be set is indicated by an element's position in the array returned by getParams. So, for example, if the parameter supplied to setNull is 2, the second element in the array returned by getParams will be an array of two or three elements.
Some methods, such as setObject and setDate have versions that take more than two parameters, with the extra parameters giving information to the driver or the DBMS. For example, the methods setDate, setTime, and setTimestamp can take a Calendar object as their third parameter. If the DBMS does not store time zone information, the driver uses the Calendar object to construct the Date, Time, or Timestamp object being set. As is true with other methods that provide additional information, the element in the array returned by getParams is an array instead of a simple Object instance.
The methods setAsciiStream, setBinaryStream, setCharacterStream, and setUnicodeStream (which is deprecated, so applications should use getCharacterStream instead) take three parameters, so for them, the element in the array returned by getParams is also an array. What is different about these setter methods is that in addition to the information provided by parameters, the array contains one of the BaseRowSet constants indicating the type of stream being set.
NOTE: The method getParams is called internally by RowSet implementations extending this class; it is not normally called by an application programmer directly.
5.0 Event Notification The BaseRowSet class provides the event notification mechanism for rowsets. It contains the field listeners, methods for adding and removing listeners, and methods for notifying listeners of changes.
A listener is an object that has implemented the RowSetListener interface. If it has been added to a RowSet object's list of listeners, it will be notified when an event occurs on that RowSet object. Each listener's implementation of the RowSetListener methods defines what that object will do when it is notified that an event has occurred.
There are three possible events for a RowSet object:
the cursor moves an individual row is changed (updated, deleted, or inserted) the contents of the entire RowSet object are changed
The BaseRowSet method used for the notification indicates the type of event that has occurred. For example, the method notifyRowChanged indicates that a row has been updated, deleted, or inserted. Each of the notification methods creates a RowSetEvent object, which is supplied to the listener in order to identify the RowSet object on which the event occurred. What the listener does with this information, which may be nothing, depends on how it was implemented.
6.0 Default Behavior A default BaseRowSet object is initialized with many starting values.
The following is true of a default RowSet instance that extends the BaseRowSet class:
Has a scrollable cursor and does not show changes
made by others.
Is updatable.
Does not show rows that have been deleted.
Has no time limit for how long a driver may take to
execute the RowSet object's command.
Has no limit for the number of rows it may contain.
Has no limit for the number of bytes a column may contain. NOTE: This
limit applies only to columns that hold values of the
following types: BINARY, VARBINARY,
LONGVARBINARY, CHAR, VARCHAR,
and LONGVARCHAR.
Will not see uncommitted data (make dirty
reads).
Has escape processing turned on.
Has its connection's type map set to null.
Has an empty Vector object for storing the values set
for the placeholder parameters in the RowSet object's command.
If other values are desired, an application must set the property values explicitly. For example, the following line of code sets the maximum number of rows for the CachedRowSet object crs to 500.
crs.setMaxRows(500); Methods implemented in extensions of this BaseRowSet class must throw an SQLException object for any violation of the defined assertions. Also, if the extending class overrides and reimplements any BaseRowSet method and encounters connectivity or underlying data source issues, that method may in addition throw an SQLException object for that reason.
An abstract class providing a RowSet object with its basic functionality. The basic functions include having properties and sending event notifications, which all JavaBeans™ components must implement. 1.0 Overview The BaseRowSet class provides the core functionality for all RowSet implementations, and all standard implementations may use this class in combination with one or more RowSet interfaces in order to provide a standard vendor-specific implementation. To clarify, all implementations must implement at least one of the RowSet interfaces (JdbcRowSet, CachedRowSet, JoinRowSet, FilteredRowSet, or WebRowSet). This means that any implementation that extends the BaseRowSet class must also implement one of the RowSet interfaces. The BaseRowSet class provides the following: Properties Fields for storing current properties Methods for getting and setting properties Event notification A complete set of setter methods for setting the parameters in a RowSet object's command Streams Fields for storing stream instances Constants for indicating the type of a stream 2.0 Setting Properties All rowsets maintain a set of properties, which will usually be set using a tool. The number and kinds of properties a rowset has will vary, depending on what the RowSet implementation does and how it gets its data. For example, rowsets that get their data from a ResultSet object need to set the properties that are required for making a database connection. If a RowSet object uses the DriverManager facility to make a connection, it needs to set a property for the JDBC URL that identifies the appropriate driver, and it needs to set the properties that give the user name and password. If, on the other hand, the rowset uses a DataSource object to make the connection, which is the preferred method, it does not need to set the property for the JDBC URL. Instead, it needs to set the property for the logical name of the data source along with the properties for the user name and password. NOTE: In order to use a DataSource object for making a connection, the DataSource object must have been registered with a naming service that uses the Java Naming and Directory Interface™ (JNDI) API. This registration is usually done by a person acting in the capacity of a system administrator. 3.0 Setting the Command and Its Parameters When a rowset gets its data from a relational database, it executes a command (a query) that produces a ResultSet object. This query is the command that is set for the RowSet object's command property. The rowset populates itself with data by reading the data from the ResultSet object into itself. If the query contains placeholders for values to be set, the BaseRowSet setter methods are used to set these values. All setter methods allow these values to be set to null if required. The following code fragment illustrates how the CachedRowSet™ object crs might have its command property set. Note that if a tool is used to set properties, this is the code that the tool would use. crs.setCommand(`SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS` `WHERE CREDIT_LIMIT > ? AND REGION = ?`); In this example, the values for CREDIT_LIMIT and REGION are placeholder parameters, which are indicated with a question mark (?). The first question mark is placeholder parameter number 1, the second question mark is placeholder parameter number 2, and so on. Any placeholder parameters must be set with values before the query can be executed. To set these placeholder parameters, the BaseRowSet class provides a set of setter methods, similar to those provided by the PreparedStatement interface, for setting values of each data type. A RowSet object stores the parameter values internally, and its execute method uses them internally to set values for the placeholder parameters before it sends the command to the DBMS to be executed. The following code fragment demonstrates setting the two parameters in the query from the previous example. crs.setInt(1, 5000); crs.setString(2, `West`); If the execute method is called at this point, the query sent to the DBMS will be: `SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS` `WHERE CREDIT_LIMIT > 5000 AND REGION = 'West'` NOTE: Setting Array, Clob, Blob and Ref objects as a command parameter, stores these values as SerialArray, SerialClob, SerialBlob and SerialRef objects respectively. 4.0 Handling of Parameters Behind the Scenes NOTE: The BaseRowSet class provides two kinds of setter methods, those that set properties and those that set placeholder parameters. The setter methods discussed in this section are those that set placeholder parameters. The placeholder parameters set with the BaseRowSet setter methods are stored as objects in an internal Hashtable object. Primitives are stored as their Object type. For example, byte is stored as Byte object, and int is stored as an Integer object. When the method execute is called, the values in the Hashtable object are substituted for the appropriate placeholder parameters in the command. A call to the method getParams returns the values stored in the Hashtable object as an array of Object instances. An element in this array may be a simple Object instance or an array (which is a type of Object). The particular setter method used determines whether an element in this array is an Object or an array. The majority of methods for setting placeholder parameters take two parameters, with the first parameter indicating which placeholder parameter is to be set, and the second parameter giving the value to be set. Methods such as setInt, setString, setBoolean, and setLong fall into this category. After these methods have been called, a call to the method getParams will return an array with the values that have been set. Each element in the array is an Object instance representing the values that have been set. The order of these values in the array is determined by the int (the first parameter) passed to the setter method. The values in the array are the values (the second parameter) passed to the setter method. In other words, the first element in the array is the value to be set for the first placeholder parameter in the RowSet object's command. The second element is the value to be set for the second placeholder parameter, and so on. Several setter methods send the driver and DBMS information beyond the value to be set. When the method getParams is called after one of these setter methods has been used, the elements in the array will themselves be arrays to accommodate the additional information. In this category, the method setNull is a special case because one version takes only two parameters (setNull(int parameterIndex, int SqlType)). Nevertheless, it requires an array to contain the information that will be passed to the driver and DBMS. The first element in this array is the value to be set, which is null, and the second element is the int supplied for sqlType, which indicates the type of SQL value that is being set to null. This information is needed by some DBMSs and is therefore required in order to ensure that applications are portable. The other version is intended to be used when the value to be set to null is a user-defined type. It takes three parameters (setNull(int parameterIndex, int sqlType, String typeName)) and also requires an array to contain the information to be passed to the driver and DBMS. The first two elements in this array are the same as for the first version of setNull. The third element, typeName, gives the SQL name of the user-defined type. As is true with the other setter methods, the number of the placeholder parameter to be set is indicated by an element's position in the array returned by getParams. So, for example, if the parameter supplied to setNull is 2, the second element in the array returned by getParams will be an array of two or three elements. Some methods, such as setObject and setDate have versions that take more than two parameters, with the extra parameters giving information to the driver or the DBMS. For example, the methods setDate, setTime, and setTimestamp can take a Calendar object as their third parameter. If the DBMS does not store time zone information, the driver uses the Calendar object to construct the Date, Time, or Timestamp object being set. As is true with other methods that provide additional information, the element in the array returned by getParams is an array instead of a simple Object instance. The methods setAsciiStream, setBinaryStream, setCharacterStream, and setUnicodeStream (which is deprecated, so applications should use getCharacterStream instead) take three parameters, so for them, the element in the array returned by getParams is also an array. What is different about these setter methods is that in addition to the information provided by parameters, the array contains one of the BaseRowSet constants indicating the type of stream being set. NOTE: The method getParams is called internally by RowSet implementations extending this class; it is not normally called by an application programmer directly. 5.0 Event Notification The BaseRowSet class provides the event notification mechanism for rowsets. It contains the field listeners, methods for adding and removing listeners, and methods for notifying listeners of changes. A listener is an object that has implemented the RowSetListener interface. If it has been added to a RowSet object's list of listeners, it will be notified when an event occurs on that RowSet object. Each listener's implementation of the RowSetListener methods defines what that object will do when it is notified that an event has occurred. There are three possible events for a RowSet object: the cursor moves an individual row is changed (updated, deleted, or inserted) the contents of the entire RowSet object are changed The BaseRowSet method used for the notification indicates the type of event that has occurred. For example, the method notifyRowChanged indicates that a row has been updated, deleted, or inserted. Each of the notification methods creates a RowSetEvent object, which is supplied to the listener in order to identify the RowSet object on which the event occurred. What the listener does with this information, which may be nothing, depends on how it was implemented. 6.0 Default Behavior A default BaseRowSet object is initialized with many starting values. The following is true of a default RowSet instance that extends the BaseRowSet class: Has a scrollable cursor and does not show changes made by others. Is updatable. Does not show rows that have been deleted. Has no time limit for how long a driver may take to execute the RowSet object's command. Has no limit for the number of rows it may contain. Has no limit for the number of bytes a column may contain. NOTE: This limit applies only to columns that hold values of the following types: BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, and LONGVARCHAR. Will not see uncommitted data (make `dirty` reads). Has escape processing turned on. Has its connection's type map set to null. Has an empty Vector object for storing the values set for the placeholder parameters in the RowSet object's command. If other values are desired, an application must set the property values explicitly. For example, the following line of code sets the maximum number of rows for the CachedRowSet object crs to 500. crs.setMaxRows(500); Methods implemented in extensions of this BaseRowSet class must throw an SQLException object for any violation of the defined assertions. Also, if the extending class overrides and reimplements any BaseRowSet method and encounters connectivity or underlying data source issues, that method may in addition throw an SQLException object for that reason.
The interface that all standard implementations of CachedRowSet must implement.
The reference implementation of the CachedRowSet interface provided by Oracle Corporation is a standard implementation. Developers may use this implementation just as it is, they may extend it, or they may choose to write their own implementations of this interface.
A CachedRowSet object is a container for rows of data that caches its rows in memory, which makes it possible to operate without always being connected to its data source. Further, it is a JavaBeans™ component and is scrollable, updatable, and serializable. A CachedRowSet object typically contains rows from a result set, but it can also contain rows from any file with a tabular format, such as a spread sheet. The reference implementation supports getting data only from a ResultSet object, but developers can extend the SyncProvider implementations to provide access to other tabular data sources.
An application can modify the data in a CachedRowSet object, and those modifications can then be propagated back to the source of the data.
A CachedRowSet object is a disconnected rowset, which means that it makes use of a connection to its data source only briefly. It connects to its data source while it is reading data to populate itself with rows and again while it is propagating changes back to its underlying data source. The rest of the time, a CachedRowSet object is disconnected, including while its data is being modified. Being disconnected makes a RowSet object much leaner and therefore much easier to pass to another component. For example, a disconnected RowSet object can be serialized and passed over the wire to a thin client such as a personal digital assistant (PDA).
1.0 Creating a CachedRowSet Object The following line of code uses the default constructor for CachedRowSet supplied in the reference implementation (RI) to create a default CachedRowSet object.
CachedRowSetImpl crs = new CachedRowSetImpl();
This new CachedRowSet object will have its properties set to the default properties of a BaseRowSet object, and, in addition, it will have an RIOptimisticProvider object as its synchronization provider. RIOptimisticProvider, one of two SyncProvider implementations included in the RI, is the default provider that the SyncFactory singleton will supply when no synchronization provider is specified.
A SyncProvider object provides a CachedRowSet object with a reader (a RowSetReader object) for reading data from a data source to populate itself with data. A reader can be implemented to read data from a ResultSet object or from a file with a tabular format. A SyncProvider object also provides a writer (a RowSetWriter object) for synchronizing any modifications to the CachedRowSet object's data made while it was disconnected with the data in the underlying data source.
A writer can be implemented to exercise various degrees of care in checking for conflicts and in avoiding them. (A conflict occurs when a value in the data source has been changed after the rowset populated itself with that value.) The RIOptimisticProvider implementation assumes there will be few or no conflicts and therefore sets no locks. It updates the data source with values from the CachedRowSet object only if there are no conflicts. Other writers can be implemented so that they always write modified data to the data source, which can be accomplished either by not checking for conflicts or, on the other end of the spectrum, by setting locks sufficient to prevent data in the data source from being changed. Still other writer implementations can be somewhere in between.
A CachedRowSet object may use any SyncProvider implementation that has been registered with the SyncFactory singleton. An application can find out which SyncProvider implementations have been registered by calling the following line of code.
java.util.Enumeration providers = SyncFactory.getRegisteredProviders();
There are two ways for a CachedRowSet object to specify which SyncProvider object it will use.
Supplying the name of the implementation to the constructor
The following line of code creates the CachedRowSet
object crs2 that is initialized with default values except that its
SyncProvider object is the one specified.
CachedRowSetImpl crs2 = new CachedRowSetImpl(
`com.fred.providers.HighAvailabilityProvider`);
Setting the SyncProvider using the CachedRowSet
method setSyncProvider
The following line of code resets the SyncProvider object
for crs, the CachedRowSet object created with the
default constructor.
crs.setSyncProvider(`com.fred.providers.HighAvailabilityProvider`);
See the comments for SyncFactory and SyncProvider for more details.
2.0 Retrieving Data from a CachedRowSet Object Data is retrieved from a CachedRowSet object by using the getter methods inherited from the ResultSet interface. The following examples, in which crs is a CachedRowSet object, demonstrate how to iterate through the rows, retrieving the column values in each row. The first example uses the version of the getter methods that take a column number; the second example uses the version that takes a column name. Column numbers are generally used when the RowSet object's command is of the form SELECT * FROM TABLENAME; column names are most commonly used when the command specifies columns by name.
while (crs.next()) {
String name = crs.getString(1);
int id = crs.getInt(2);
Clob comment = crs.getClob(3);
short dept = crs.getShort(4);
System.out.println(name id
comment
dept);
}
while (crs.next()) {
String name = crs.getString(NAME
);
int id = crs.getInt(ID
);
Clob comment = crs.getClob(COM
);
short dept = crs.getShort(DEPT
);
System.out.println(name id
comment
dept);
}
2.1 Retrieving RowSetMetaData
An application can get information about the columns in a CachedRowSet
object by calling ResultSetMetaData and RowSetMetaData
methods on a RowSetMetaData object. The following code fragment,
in which crs is a CachedRowSet object, illustrates the process.
The first line creates a RowSetMetaData object with information
about the columns in crs. The method getMetaData,
inherited from the ResultSet interface, returns a
ResultSetMetaData object, which is cast to a
RowSetMetaData object before being assigned to the variable
rsmd. The second line finds out how many columns jrs has, and
the third line gets the JDBC type of values stored in the second column of
jrs.
RowSetMetaData rsmd = (RowSetMetaData)crs.getMetaData();
int count = rsmd.getColumnCount();
int type = rsmd.getColumnType(2);
The RowSetMetaData interface differs from the ResultSetMetaData interface in two ways.
It includes setter methods: A RowSet object uses these methods internally when it is populated with data from a different ResultSet object.
It contains fewer getter methods: Some ResultSetMetaData methods to not apply to a RowSet object. For example, methods retrieving whether a column value is writable or read only do not apply because all of a RowSet object's columns will be writable or read only, depending on whether the rowset is updatable or not.
NOTE: In order to return a RowSetMetaData object, implementations must override the getMetaData() method defined in java.sql.ResultSet and return a RowSetMetaData object.
3.0 Updating a CachedRowSet Object Updating a CachedRowSet object is similar to updating a ResultSet object, but because the rowset is not connected to its data source while it is being updated, it must take an additional step to effect changes in its underlying data source. After calling the method updateRow or insertRow, a CachedRowSet object must also call the method acceptChanges to have updates written to the data source. The following example, in which the cursor is on a row in the CachedRowSet object crs, shows the code required to update two column values in the current row and also update the RowSet object's underlying data source.
crs.updateShort(3, 58);
crs.updateInt(4, 150000);
crs.updateRow();
crs.acceptChanges();
The next example demonstrates moving to the insert row, building a new row on the insert row, inserting it into the rowset, and then calling the method acceptChanges to add the new row to the underlying data source. Note that as with the getter methods, the updater methods may take either a column index or a column name to designate the column being acted upon.
crs.moveToInsertRow();
crs.updateString(`Name`, `Shakespeare`);
crs.updateInt(`ID`, 10098347);
crs.updateShort(`Age`, 58);
crs.updateInt(`Sal`, 150000);
crs.insertRow();
crs.moveToCurrentRow();
crs.acceptChanges();
NOTE: Where the insertRow() method inserts the contents of a CachedRowSet object's insert row is implementation-defined. The reference implementation for the CachedRowSet interface inserts a new row immediately following the current row, but it could be implemented to insert new rows in any number of other places.
Another thing to note about these examples is how they use the method acceptChanges. It is this method that propagates changes in a CachedRowSet object back to the underlying data source, calling on the RowSet object's writer internally to write changes to the data source. To do this, the writer has to incur the expense of establishing a connection with that data source. The preceding two code fragments call the method acceptChanges immediately after calling updateRow or insertRow. However, when there are multiple rows being changed, it is more efficient to call acceptChanges after all calls to updateRow and insertRow have been made. If acceptChanges is called only once, only one connection needs to be established.
4.0 Updating the Underlying Data Source When the method acceptChanges is executed, the CachedRowSet object's writer, a RowSetWriterImpl object, is called behind the scenes to write the changes made to the rowset to the underlying data source. The writer is implemented to make a connection to the data source and write updates to it.
A writer is made available through an implementation of the
SyncProvider interface, as discussed in section 1,
Creating a CachedRowSet Object.
The default reference implementation provider, RIOptimisticProvider,
has its writer implemented to use an optimistic concurrency control
mechanism. That is, it maintains no locks in the underlying database while
the rowset is disconnected from the database and simply checks to see if there
are any conflicts before writing data to the data source. If there are any
conflicts, it does not write anything to the data source.
The reader/writer facility provided by the SyncProvider class is pluggable, allowing for the customization of data retrieval and updating. If a different concurrency control mechanism is desired, a different implementation of SyncProvider can be plugged in using the method setSyncProvider.
In order to use the optimistic concurrency control routine, the RIOptismisticProvider maintains both its current value and its original value (the value it had immediately preceding the current value). Note that if no changes have been made to the data in a RowSet object, its current values and its original values are the same, both being the values with which the RowSet object was initially populated. However, once any values in the RowSet object have been changed, the current values and the original values will be different, though at this stage, the original values are still the initial values. With any subsequent changes to data in a RowSet object, its original values and current values will still differ, but its original values will be the values that were previously the current values.
Keeping track of original values allows the writer to compare the RowSet object's original value with the value in the database. If the values in the database differ from the RowSet object's original values, which means that the values in the database have been changed, there is a conflict. Whether a writer checks for conflicts, what degree of checking it does, and how it handles conflicts all depend on how it is implemented.
5.0 Registering and Notifying Listeners Being JavaBeans components, all rowsets participate in the JavaBeans event model, inheriting methods for registering listeners and notifying them of changes from the BaseRowSet class. A listener for a CachedRowSet object is a component that wants to be notified whenever there is a change in the rowset. For example, if a CachedRowSet object contains the results of a query and those results are being displayed in, say, a table and a bar graph, the table and bar graph could be registered as listeners with the rowset so that they can update themselves to reflect changes. To become listeners, the table and bar graph classes must implement the RowSetListener interface. Then they can be added to the CachedRowSet object's list of listeners, as is illustrated in the following lines of code.
crs.addRowSetListener(table); crs.addRowSetListener(barGraph); Each CachedRowSet method that moves the cursor or changes data also notifies registered listeners of the changes, so table and barGraph will be notified when there is a change in crs.
6.0 Passing Data to Thin Clients One of the main reasons to use a CachedRowSet object is to pass data between different components of an application. Because it is serializable, a CachedRowSet object can be used, for example, to send the result of a query executed by an enterprise JavaBeans component running in a server environment over a network to a client running in a web browser.
While a CachedRowSet object is disconnected, it can be much
leaner than a ResultSet object with the same data.
As a result, it can be especially suitable for sending data to a thin client
such as a PDA, where it would be inappropriate to use a JDBC driver
due to resource limitations or security considerations.
Thus, a CachedRowSet object provides a means to get rows in
without the need to implement the full JDBC API.
7.0 Scrolling and Updating
A second major use for CachedRowSet objects is to provide
scrolling and updating for ResultSet objects that
do not provide these capabilities themselves. In other words, a
CachedRowSet object can be used to augment the
capabilities of a JDBC technology-enabled driver (hereafter called a
JDBC driver
) when the DBMS does not provide full support for scrolling and
updating. To achieve the effect of making a non-scrollble and read-only
ResultSet object scrollable and updatable, a programmer
simply needs to create a CachedRowSet object populated
with that ResultSet object's data. This is demonstrated
in the following code fragment, where stmt is a
Statement object.
ResultSet rs = stmt.executeQuery(SELECT * FROM EMPLOYEES
);
CachedRowSetImpl crs = new CachedRowSetImpl();
crs.populate(rs);
The object crs now contains the data from the table EMPLOYEES, just as the object rs does. The difference is that the cursor for crs can be moved forward, backward, or to a particular row even if the cursor for rs can move only forward. In addition, crs is updatable even if rs is not because by default, a CachedRowSet object is both scrollable and updatable.
In summary, a CachedRowSet object can be thought of as simply a disconnected set of rows that are being cached outside of a data source. Being thin and serializable, it can easily be sent across a wire, and it is well suited to sending data to a thin client. However, a CachedRowSet object does have a limitation: It is limited in size by the amount of data it can store in memory at one time.
8.0 Getting Universal Data Access Another advantage of the CachedRowSet class is that it makes it possible to retrieve and store data from sources other than a relational database. The reader for a rowset can be implemented to read and populate its rowset with data from any tabular data source, including a spreadsheet or flat file. Because both a CachedRowSet object and its metadata can be created from scratch, a component that acts as a factory for rowsets can use this capability to create a rowset containing data from non-SQL data sources. Nevertheless, it is expected that most of the time, CachedRowSet objects will contain data that was fetched from an SQL database using the JDBC API.
9.0 Setting Properties All rowsets maintain a set of properties, which will usually be set using a tool. The number and kinds of properties a rowset has will vary, depending on what the rowset does and how it gets its data. For example, rowsets that get their data from a ResultSet object need to set the properties that are required for making a database connection. If a rowset uses the DriverManager facility to make a connection, it needs to set a property for the JDBC URL that identifies the appropriate driver, and it needs to set the properties that give the user name and password. If, on the other hand, the rowset uses a DataSource object to make the connection, which is the preferred method, it does not need to set the property for the JDBC URL. Instead, it needs to set properties for the logical name of the data source, for the user name, and for the password.
NOTE: In order to use a DataSource object for making a connection, the DataSource object must have been registered with a naming service that uses the Java Naming and Directory Interface™ (JNDI) API. This registration is usually done by a person acting in the capacity of a system administrator.
In order to be able to populate itself with data from a database, a rowset needs to set a command property. This property is a query that is a PreparedStatement object, which allows the query to have parameter placeholders that are set at run time, as opposed to design time. To set these placeholder parameters with values, a rowset provides setter methods for setting values of each data type, similar to the setter methods provided by the PreparedStatement interface.
The following code fragment illustrates how the CachedRowSet object crs might have its command property set. Note that if a tool is used to set properties, this is the code that the tool would use.
crs.setCommand(SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS
WHERE CREDIT_LIMIT > ? AND REGION = ?
);
The values that will be used to set the command's placeholder parameters are contained in the RowSet object's params field, which is a Vector object. The CachedRowSet class provides a set of setter methods for setting the elements in its params field. The following code fragment demonstrates setting the two parameters in the query from the previous example.
crs.setInt(1, 5000);
crs.setString(2, West
);
The params field now contains two elements, each of which is
an array two elements long. The first element is the parameter number;
the second is the value to be set.
In this case, the first element of params is
1, 5000, and the second element is 2,
West
. When an application calls the method
execute, it will in turn call on this RowSet object's reader,
which will in turn invoke its readData method. As part of
its implementation, readData will get the values in
params and use them to set the command's placeholder
parameters.
The following code fragment gives an idea of how the reader
does this, after obtaining the Connection object
con.
PreparedStatement pstmt = con.prepareStatement(crs.getCommand()); reader.decodeParams(); // decodeParams figures out which setter methods to use and does something // like the following: // for (i = 0; i < params.length; i++) { // pstmt.setObject(i 1, params[i]); // }
At this point, the command for crs is the query SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS WHERE CREDIT_LIMIT > 5000 AND REGION =
West`. After the readData method executes
this command with the following line of code, it will have the data from
rs with which to populate crs.
ResultSet rs = pstmt.executeQuery();
The preceding code fragments give an idea of what goes on behind the scenes; they would not appear in an application, which would not invoke methods like readData and decodeParams. In contrast, the following code fragment shows what an application might do. It sets the rowset's command, sets the command's parameters, and executes the command. Simply by calling the execute method, crs populates itself with the requested data from the table CUSTOMERS.
crs.setCommand(SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS
WHERE CREDIT_LIMIT > ? AND REGION = ?
);
crs.setInt(1, 5000);
crs.setString(2, West
);
crs.execute();
10.0 Paging Data Because a CachedRowSet object stores data in memory, the amount of data that it can contain at any one time is determined by the amount of memory available. To get around this limitation, a CachedRowSet object can retrieve data from a ResultSet object in chunks of data, called pages. To take advantage of this mechanism, an application sets the number of rows to be included in a page using the method setPageSize. In other words, if the page size is set to five, a chunk of five rows of data will be fetched from the data source at one time. An application can also optionally set the maximum number of rows that may be fetched at one time. If the maximum number of rows is set to zero, or no maximum number of rows is set, there is no limit to the number of rows that may be fetched at a time.
After properties have been set, the CachedRowSet object must be populated with data using either the method populate or the method execute. The following lines of code demonstrate using the method populate. Note that this version of the method takes two parameters, a ResultSet handle and the row in the ResultSet object from which to start retrieving rows.
CachedRowSet crs = new CachedRowSetImpl();
crs.setMaxRows(20);
crs.setPageSize(4);
crs.populate(rsHandle, 10);
When this code runs, crs will be populated with four rows from rsHandle starting with the tenth row.
The next code fragment shows populating a CachedRowSet object using the method execute, which may or may not take a Connection object as a parameter. This code passes execute the Connection object conHandle.
Note that there are two differences between the following code fragment and the previous one. First, the method setMaxRows is not called, so there is no limit set for the number of rows that crs may contain. (Remember that crs always has the overriding limit of how much data it can store in memory.) The second difference is that the you cannot pass the method execute the number of the row in the ResultSet object from which to start retrieving rows. This method always starts with the first row.
CachedRowSet crs = new CachedRowSetImpl();
crs.setPageSize(5);
crs.execute(conHandle);
After this code has run, crs will contain five rows of data from the ResultSet object produced by the command for crs. The writer for crs will use conHandle to connect to the data source and execute the command for crs. An application is then able to operate on the data in crs in the same way that it would operate on data in any other CachedRowSet object.
To access the next page (chunk of data), an application calls the method nextPage. This method creates a new CachedRowSet object and fills it with the next page of data. For example, assume that the CachedRowSet object's command returns a ResultSet object rs with 1000 rows of data. If the page size has been set to 100, the first call to the method nextPage will create a CachedRowSet object containing the first 100 rows of rs. After doing what it needs to do with the data in these first 100 rows, the application can again call the method nextPage to create another CachedRowSet object with the second 100 rows from rs. The data from the first CachedRowSet object will no longer be in memory because it is replaced with the data from the second CachedRowSet object. After the tenth call to the method nextPage, the tenth CachedRowSet object will contain the last 100 rows of data from rs, which are stored in memory. At any given time, the data from only one CachedRowSet object is stored in memory.
The method nextPage returns true as long as the current page is not the last page of rows and false when there are no more pages. It can therefore be used in a while loop to retrieve all of the pages, as is demonstrated in the following lines of code.
CachedRowSet crs = CachedRowSetImpl();
crs.setPageSize(100);
crs.execute(conHandle);
while(crs.nextPage()) {
while(crs.next()) {
. . . // operate on chunks (of 100 rows each) in crs,
// row by row
}
}
After this code fragment has been run, the application will have traversed all 1000 rows, but it will have had no more than 100 rows in memory at a time.
The CachedRowSet interface also defines the method previousPage. Just as the method nextPage is analogous to the ResultSet method next, the method previousPage is analogous to the ResultSet method previous. Similar to the method nextPage, previousPage creates a CachedRowSet object containing the number of rows set as the page size. So, for instance, the method previousPage could be used in a while loop at the end of the preceding code fragment to navigate back through the pages from the last page to the first page. The method previousPage is also similar to nextPage in that it can be used in a while loop, except that it returns true as long as there is another page preceding it and false when there are no more pages ahead of it.
By positioning the cursor after the last row for each page, as is done in the following code fragment, the method previous navigates from the last row to the first row in each page. The code could also have left the cursor before the first row on each page and then used the method next in a while loop to navigate each page from the first row to the last row.
The following code fragment assumes a continuation from the previous code fragment, meaning that the cursor for the tenth CachedRowSet object is on the last row. The code moves the cursor to after the last row so that the first call to the method previous will put the cursor back on the last row. After going through all of the rows in the last page (the CachedRowSet object crs), the code then enters the while loop to get to the ninth page, go through the rows backwards, go to the eighth page, go through the rows backwards, and so on to the first row of the first page.
crs.afterLast();
while(crs.previous()) {
. . . // navigate through the rows, last to first
{
while(crs.previousPage()) {
crs.afterLast();
while(crs.previous()) {
. . . // go from the last row to the first row of each page
}
}
The interface that all standard implementations of CachedRowSet must implement. The reference implementation of the CachedRowSet interface provided by Oracle Corporation is a standard implementation. Developers may use this implementation just as it is, they may extend it, or they may choose to write their own implementations of this interface. A CachedRowSet object is a container for rows of data that caches its rows in memory, which makes it possible to operate without always being connected to its data source. Further, it is a JavaBeans™ component and is scrollable, updatable, and serializable. A CachedRowSet object typically contains rows from a result set, but it can also contain rows from any file with a tabular format, such as a spread sheet. The reference implementation supports getting data only from a ResultSet object, but developers can extend the SyncProvider implementations to provide access to other tabular data sources. An application can modify the data in a CachedRowSet object, and those modifications can then be propagated back to the source of the data. A CachedRowSet object is a disconnected rowset, which means that it makes use of a connection to its data source only briefly. It connects to its data source while it is reading data to populate itself with rows and again while it is propagating changes back to its underlying data source. The rest of the time, a CachedRowSet object is disconnected, including while its data is being modified. Being disconnected makes a RowSet object much leaner and therefore much easier to pass to another component. For example, a disconnected RowSet object can be serialized and passed over the wire to a thin client such as a personal digital assistant (PDA). 1.0 Creating a CachedRowSet Object The following line of code uses the default constructor for CachedRowSet supplied in the reference implementation (RI) to create a default CachedRowSet object. CachedRowSetImpl crs = new CachedRowSetImpl(); This new CachedRowSet object will have its properties set to the default properties of a BaseRowSet object, and, in addition, it will have an RIOptimisticProvider object as its synchronization provider. RIOptimisticProvider, one of two SyncProvider implementations included in the RI, is the default provider that the SyncFactory singleton will supply when no synchronization provider is specified. A SyncProvider object provides a CachedRowSet object with a reader (a RowSetReader object) for reading data from a data source to populate itself with data. A reader can be implemented to read data from a ResultSet object or from a file with a tabular format. A SyncProvider object also provides a writer (a RowSetWriter object) for synchronizing any modifications to the CachedRowSet object's data made while it was disconnected with the data in the underlying data source. A writer can be implemented to exercise various degrees of care in checking for conflicts and in avoiding them. (A conflict occurs when a value in the data source has been changed after the rowset populated itself with that value.) The RIOptimisticProvider implementation assumes there will be few or no conflicts and therefore sets no locks. It updates the data source with values from the CachedRowSet object only if there are no conflicts. Other writers can be implemented so that they always write modified data to the data source, which can be accomplished either by not checking for conflicts or, on the other end of the spectrum, by setting locks sufficient to prevent data in the data source from being changed. Still other writer implementations can be somewhere in between. A CachedRowSet object may use any SyncProvider implementation that has been registered with the SyncFactory singleton. An application can find out which SyncProvider implementations have been registered by calling the following line of code. java.util.Enumeration providers = SyncFactory.getRegisteredProviders(); There are two ways for a CachedRowSet object to specify which SyncProvider object it will use. Supplying the name of the implementation to the constructor The following line of code creates the CachedRowSet object crs2 that is initialized with default values except that its SyncProvider object is the one specified. CachedRowSetImpl crs2 = new CachedRowSetImpl( `com.fred.providers.HighAvailabilityProvider`); Setting the SyncProvider using the CachedRowSet method setSyncProvider The following line of code resets the SyncProvider object for crs, the CachedRowSet object created with the default constructor. crs.setSyncProvider(`com.fred.providers.HighAvailabilityProvider`); See the comments for SyncFactory and SyncProvider for more details. 2.0 Retrieving Data from a CachedRowSet Object Data is retrieved from a CachedRowSet object by using the getter methods inherited from the ResultSet interface. The following examples, in which crs is a CachedRowSet object, demonstrate how to iterate through the rows, retrieving the column values in each row. The first example uses the version of the getter methods that take a column number; the second example uses the version that takes a column name. Column numbers are generally used when the RowSet object's command is of the form SELECT * FROM TABLENAME; column names are most commonly used when the command specifies columns by name. while (crs.next()) { String name = crs.getString(1); int id = crs.getInt(2); Clob comment = crs.getClob(3); short dept = crs.getShort(4); System.out.println(name ` ` id ` ` comment ` ` dept); } while (crs.next()) { String name = crs.getString(`NAME`); int id = crs.getInt(`ID`); Clob comment = crs.getClob(`COM`); short dept = crs.getShort(`DEPT`); System.out.println(name ` ` id ` ` comment ` ` dept); } 2.1 Retrieving RowSetMetaData An application can get information about the columns in a CachedRowSet object by calling ResultSetMetaData and RowSetMetaData methods on a RowSetMetaData object. The following code fragment, in which crs is a CachedRowSet object, illustrates the process. The first line creates a RowSetMetaData object with information about the columns in crs. The method getMetaData, inherited from the ResultSet interface, returns a ResultSetMetaData object, which is cast to a RowSetMetaData object before being assigned to the variable rsmd. The second line finds out how many columns jrs has, and the third line gets the JDBC type of values stored in the second column of jrs. RowSetMetaData rsmd = (RowSetMetaData)crs.getMetaData(); int count = rsmd.getColumnCount(); int type = rsmd.getColumnType(2); The RowSetMetaData interface differs from the ResultSetMetaData interface in two ways. It includes setter methods: A RowSet object uses these methods internally when it is populated with data from a different ResultSet object. It contains fewer getter methods: Some ResultSetMetaData methods to not apply to a RowSet object. For example, methods retrieving whether a column value is writable or read only do not apply because all of a RowSet object's columns will be writable or read only, depending on whether the rowset is updatable or not. NOTE: In order to return a RowSetMetaData object, implementations must override the getMetaData() method defined in java.sql.ResultSet and return a RowSetMetaData object. 3.0 Updating a CachedRowSet Object Updating a CachedRowSet object is similar to updating a ResultSet object, but because the rowset is not connected to its data source while it is being updated, it must take an additional step to effect changes in its underlying data source. After calling the method updateRow or insertRow, a CachedRowSet object must also call the method acceptChanges to have updates written to the data source. The following example, in which the cursor is on a row in the CachedRowSet object crs, shows the code required to update two column values in the current row and also update the RowSet object's underlying data source. crs.updateShort(3, 58); crs.updateInt(4, 150000); crs.updateRow(); crs.acceptChanges(); The next example demonstrates moving to the insert row, building a new row on the insert row, inserting it into the rowset, and then calling the method acceptChanges to add the new row to the underlying data source. Note that as with the getter methods, the updater methods may take either a column index or a column name to designate the column being acted upon. crs.moveToInsertRow(); crs.updateString(`Name`, `Shakespeare`); crs.updateInt(`ID`, 10098347); crs.updateShort(`Age`, 58); crs.updateInt(`Sal`, 150000); crs.insertRow(); crs.moveToCurrentRow(); crs.acceptChanges(); NOTE: Where the insertRow() method inserts the contents of a CachedRowSet object's insert row is implementation-defined. The reference implementation for the CachedRowSet interface inserts a new row immediately following the current row, but it could be implemented to insert new rows in any number of other places. Another thing to note about these examples is how they use the method acceptChanges. It is this method that propagates changes in a CachedRowSet object back to the underlying data source, calling on the RowSet object's writer internally to write changes to the data source. To do this, the writer has to incur the expense of establishing a connection with that data source. The preceding two code fragments call the method acceptChanges immediately after calling updateRow or insertRow. However, when there are multiple rows being changed, it is more efficient to call acceptChanges after all calls to updateRow and insertRow have been made. If acceptChanges is called only once, only one connection needs to be established. 4.0 Updating the Underlying Data Source When the method acceptChanges is executed, the CachedRowSet object's writer, a RowSetWriterImpl object, is called behind the scenes to write the changes made to the rowset to the underlying data source. The writer is implemented to make a connection to the data source and write updates to it. A writer is made available through an implementation of the SyncProvider interface, as discussed in section 1, `Creating a CachedRowSet Object.` The default reference implementation provider, RIOptimisticProvider, has its writer implemented to use an optimistic concurrency control mechanism. That is, it maintains no locks in the underlying database while the rowset is disconnected from the database and simply checks to see if there are any conflicts before writing data to the data source. If there are any conflicts, it does not write anything to the data source. The reader/writer facility provided by the SyncProvider class is pluggable, allowing for the customization of data retrieval and updating. If a different concurrency control mechanism is desired, a different implementation of SyncProvider can be plugged in using the method setSyncProvider. In order to use the optimistic concurrency control routine, the RIOptismisticProvider maintains both its current value and its original value (the value it had immediately preceding the current value). Note that if no changes have been made to the data in a RowSet object, its current values and its original values are the same, both being the values with which the RowSet object was initially populated. However, once any values in the RowSet object have been changed, the current values and the original values will be different, though at this stage, the original values are still the initial values. With any subsequent changes to data in a RowSet object, its original values and current values will still differ, but its original values will be the values that were previously the current values. Keeping track of original values allows the writer to compare the RowSet object's original value with the value in the database. If the values in the database differ from the RowSet object's original values, which means that the values in the database have been changed, there is a conflict. Whether a writer checks for conflicts, what degree of checking it does, and how it handles conflicts all depend on how it is implemented. 5.0 Registering and Notifying Listeners Being JavaBeans components, all rowsets participate in the JavaBeans event model, inheriting methods for registering listeners and notifying them of changes from the BaseRowSet class. A listener for a CachedRowSet object is a component that wants to be notified whenever there is a change in the rowset. For example, if a CachedRowSet object contains the results of a query and those results are being displayed in, say, a table and a bar graph, the table and bar graph could be registered as listeners with the rowset so that they can update themselves to reflect changes. To become listeners, the table and bar graph classes must implement the RowSetListener interface. Then they can be added to the CachedRowSet object's list of listeners, as is illustrated in the following lines of code. crs.addRowSetListener(table); crs.addRowSetListener(barGraph); Each CachedRowSet method that moves the cursor or changes data also notifies registered listeners of the changes, so table and barGraph will be notified when there is a change in crs. 6.0 Passing Data to Thin Clients One of the main reasons to use a CachedRowSet object is to pass data between different components of an application. Because it is serializable, a CachedRowSet object can be used, for example, to send the result of a query executed by an enterprise JavaBeans component running in a server environment over a network to a client running in a web browser. While a CachedRowSet object is disconnected, it can be much leaner than a ResultSet object with the same data. As a result, it can be especially suitable for sending data to a thin client such as a PDA, where it would be inappropriate to use a JDBC driver due to resource limitations or security considerations. Thus, a CachedRowSet object provides a means to `get rows in` without the need to implement the full JDBC API. 7.0 Scrolling and Updating A second major use for CachedRowSet objects is to provide scrolling and updating for ResultSet objects that do not provide these capabilities themselves. In other words, a CachedRowSet object can be used to augment the capabilities of a JDBC technology-enabled driver (hereafter called a `JDBC driver`) when the DBMS does not provide full support for scrolling and updating. To achieve the effect of making a non-scrollble and read-only ResultSet object scrollable and updatable, a programmer simply needs to create a CachedRowSet object populated with that ResultSet object's data. This is demonstrated in the following code fragment, where stmt is a Statement object. ResultSet rs = stmt.executeQuery(`SELECT * FROM EMPLOYEES`); CachedRowSetImpl crs = new CachedRowSetImpl(); crs.populate(rs); The object crs now contains the data from the table EMPLOYEES, just as the object rs does. The difference is that the cursor for crs can be moved forward, backward, or to a particular row even if the cursor for rs can move only forward. In addition, crs is updatable even if rs is not because by default, a CachedRowSet object is both scrollable and updatable. In summary, a CachedRowSet object can be thought of as simply a disconnected set of rows that are being cached outside of a data source. Being thin and serializable, it can easily be sent across a wire, and it is well suited to sending data to a thin client. However, a CachedRowSet object does have a limitation: It is limited in size by the amount of data it can store in memory at one time. 8.0 Getting Universal Data Access Another advantage of the CachedRowSet class is that it makes it possible to retrieve and store data from sources other than a relational database. The reader for a rowset can be implemented to read and populate its rowset with data from any tabular data source, including a spreadsheet or flat file. Because both a CachedRowSet object and its metadata can be created from scratch, a component that acts as a factory for rowsets can use this capability to create a rowset containing data from non-SQL data sources. Nevertheless, it is expected that most of the time, CachedRowSet objects will contain data that was fetched from an SQL database using the JDBC API. 9.0 Setting Properties All rowsets maintain a set of properties, which will usually be set using a tool. The number and kinds of properties a rowset has will vary, depending on what the rowset does and how it gets its data. For example, rowsets that get their data from a ResultSet object need to set the properties that are required for making a database connection. If a rowset uses the DriverManager facility to make a connection, it needs to set a property for the JDBC URL that identifies the appropriate driver, and it needs to set the properties that give the user name and password. If, on the other hand, the rowset uses a DataSource object to make the connection, which is the preferred method, it does not need to set the property for the JDBC URL. Instead, it needs to set properties for the logical name of the data source, for the user name, and for the password. NOTE: In order to use a DataSource object for making a connection, the DataSource object must have been registered with a naming service that uses the Java Naming and Directory Interface™ (JNDI) API. This registration is usually done by a person acting in the capacity of a system administrator. In order to be able to populate itself with data from a database, a rowset needs to set a command property. This property is a query that is a PreparedStatement object, which allows the query to have parameter placeholders that are set at run time, as opposed to design time. To set these placeholder parameters with values, a rowset provides setter methods for setting values of each data type, similar to the setter methods provided by the PreparedStatement interface. The following code fragment illustrates how the CachedRowSet object crs might have its command property set. Note that if a tool is used to set properties, this is the code that the tool would use. crs.setCommand(`SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS ` `WHERE CREDIT_LIMIT > ? AND REGION = ?`); The values that will be used to set the command's placeholder parameters are contained in the RowSet object's params field, which is a Vector object. The CachedRowSet class provides a set of setter methods for setting the elements in its params field. The following code fragment demonstrates setting the two parameters in the query from the previous example. crs.setInt(1, 5000); crs.setString(2, `West`); The params field now contains two elements, each of which is an array two elements long. The first element is the parameter number; the second is the value to be set. In this case, the first element of params is 1, 5000, and the second element is 2, `West`. When an application calls the method execute, it will in turn call on this RowSet object's reader, which will in turn invoke its readData method. As part of its implementation, readData will get the values in params and use them to set the command's placeholder parameters. The following code fragment gives an idea of how the reader does this, after obtaining the Connection object con. PreparedStatement pstmt = con.prepareStatement(crs.getCommand()); reader.decodeParams(); // decodeParams figures out which setter methods to use and does something // like the following: // for (i = 0; i < params.length; i++) { // pstmt.setObject(i 1, params[i]); // } At this point, the command for crs is the query `SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS WHERE CREDIT_LIMIT > 5000 AND REGION = `West`. After the readData method executes this command with the following line of code, it will have the data from rs with which to populate crs. ResultSet rs = pstmt.executeQuery(); The preceding code fragments give an idea of what goes on behind the scenes; they would not appear in an application, which would not invoke methods like readData and decodeParams. In contrast, the following code fragment shows what an application might do. It sets the rowset's command, sets the command's parameters, and executes the command. Simply by calling the execute method, crs populates itself with the requested data from the table CUSTOMERS. crs.setCommand(`SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS` `WHERE CREDIT_LIMIT > ? AND REGION = ?`); crs.setInt(1, 5000); crs.setString(2, `West`); crs.execute(); 10.0 Paging Data Because a CachedRowSet object stores data in memory, the amount of data that it can contain at any one time is determined by the amount of memory available. To get around this limitation, a CachedRowSet object can retrieve data from a ResultSet object in chunks of data, called pages. To take advantage of this mechanism, an application sets the number of rows to be included in a page using the method setPageSize. In other words, if the page size is set to five, a chunk of five rows of data will be fetched from the data source at one time. An application can also optionally set the maximum number of rows that may be fetched at one time. If the maximum number of rows is set to zero, or no maximum number of rows is set, there is no limit to the number of rows that may be fetched at a time. After properties have been set, the CachedRowSet object must be populated with data using either the method populate or the method execute. The following lines of code demonstrate using the method populate. Note that this version of the method takes two parameters, a ResultSet handle and the row in the ResultSet object from which to start retrieving rows. CachedRowSet crs = new CachedRowSetImpl(); crs.setMaxRows(20); crs.setPageSize(4); crs.populate(rsHandle, 10); When this code runs, crs will be populated with four rows from rsHandle starting with the tenth row. The next code fragment shows populating a CachedRowSet object using the method execute, which may or may not take a Connection object as a parameter. This code passes execute the Connection object conHandle. Note that there are two differences between the following code fragment and the previous one. First, the method setMaxRows is not called, so there is no limit set for the number of rows that crs may contain. (Remember that crs always has the overriding limit of how much data it can store in memory.) The second difference is that the you cannot pass the method execute the number of the row in the ResultSet object from which to start retrieving rows. This method always starts with the first row. CachedRowSet crs = new CachedRowSetImpl(); crs.setPageSize(5); crs.execute(conHandle); After this code has run, crs will contain five rows of data from the ResultSet object produced by the command for crs. The writer for crs will use conHandle to connect to the data source and execute the command for crs. An application is then able to operate on the data in crs in the same way that it would operate on data in any other CachedRowSet object. To access the next page (chunk of data), an application calls the method nextPage. This method creates a new CachedRowSet object and fills it with the next page of data. For example, assume that the CachedRowSet object's command returns a ResultSet object rs with 1000 rows of data. If the page size has been set to 100, the first call to the method nextPage will create a CachedRowSet object containing the first 100 rows of rs. After doing what it needs to do with the data in these first 100 rows, the application can again call the method nextPage to create another CachedRowSet object with the second 100 rows from rs. The data from the first CachedRowSet object will no longer be in memory because it is replaced with the data from the second CachedRowSet object. After the tenth call to the method nextPage, the tenth CachedRowSet object will contain the last 100 rows of data from rs, which are stored in memory. At any given time, the data from only one CachedRowSet object is stored in memory. The method nextPage returns true as long as the current page is not the last page of rows and false when there are no more pages. It can therefore be used in a while loop to retrieve all of the pages, as is demonstrated in the following lines of code. CachedRowSet crs = CachedRowSetImpl(); crs.setPageSize(100); crs.execute(conHandle); while(crs.nextPage()) { while(crs.next()) { . . . // operate on chunks (of 100 rows each) in crs, // row by row } } After this code fragment has been run, the application will have traversed all 1000 rows, but it will have had no more than 100 rows in memory at a time. The CachedRowSet interface also defines the method previousPage. Just as the method nextPage is analogous to the ResultSet method next, the method previousPage is analogous to the ResultSet method previous. Similar to the method nextPage, previousPage creates a CachedRowSet object containing the number of rows set as the page size. So, for instance, the method previousPage could be used in a while loop at the end of the preceding code fragment to navigate back through the pages from the last page to the first page. The method previousPage is also similar to nextPage in that it can be used in a while loop, except that it returns true as long as there is another page preceding it and false when there are no more pages ahead of it. By positioning the cursor after the last row for each page, as is done in the following code fragment, the method previous navigates from the last row to the first row in each page. The code could also have left the cursor before the first row on each page and then used the method next in a while loop to navigate each page from the first row to the last row. The following code fragment assumes a continuation from the previous code fragment, meaning that the cursor for the tenth CachedRowSet object is on the last row. The code moves the cursor to after the last row so that the first call to the method previous will put the cursor back on the last row. After going through all of the rows in the last page (the CachedRowSet object crs), the code then enters the while loop to get to the ninth page, go through the rows backwards, go to the eighth page, go through the rows backwards, and so on to the first row of the first page. crs.afterLast(); while(crs.previous()) { . . . // navigate through the rows, last to first { while(crs.previousPage()) { crs.afterLast(); while(crs.previous()) { . . . // go from the last row to the first row of each page } }
No vars found in this namespace.
The standard interface that all standard implementations of FilteredRowSet must implement. The FilteredRowSetImpl 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.
1.0 Background
There are occasions when a RowSet 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 RowSet implementations; however, this is an impractical approach for lightweight components such as disconnected RowSet objects. The FilteredRowSet interface seeks to address this need without supplying a heavyweight query language along with the processing that such a query language would require.
A JDBC FilteredRowSet standard implementation implements the RowSet interfaces and extends the CachedRowSet™ class. The CachedRowSet class provides a set of protected cursor manipulation methods, which a FilteredRowSet implementation can override to supply filtering support.
2.0 Predicate Sharing
If a FilteredRowSet implementation is shared using the inherited createShared method in parent interfaces, the Predicate should be shared without modification by all FilteredRowSet instance clones.
3.0 Usage
By implementing a Predicate (see example in Predicate class JavaDoc), a FilteredRowSet could then be used as described below.
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
In the example above, we initialize a Range object which implements the Predicate interface. This object expresses the following constraints: All rows outputted or modified from this FilteredRowSet object must fall between the values 'Alpha' and 'Bravo' both values inclusive, in the column 'columnName'. If a filter is applied to a FilteredRowSet object that contains no data that falls within the range of the filter, no rows are returned.
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.
4.0 Updating a FilteredRowSet Object The predicate set on a FilteredRowSet object applies a criterion on all rows in a RowSet object to manage a subset of rows in a RowSet object. This criterion governs the subset of rows that are visible and also defines which rows can be modified, deleted or inserted.
Therefore, the predicate set on a FilteredRowSet object must be considered as bi-directional and the set criterion as the gating mechanism for all views and updates to the FilteredRowSet object. Any attempt to update the FilteredRowSet that violates the criterion will result in a SQLException object being thrown.
The FilteredRowSet range criterion can be modified by applying a new Predicate object to the FilteredRowSet instance at any time. This is possible if no additional references to the FilteredRowSet object are detected. A new filter has has an immediate effect on criterion enforcement within the FilteredRowSet object, and all subsequent views and updates will be subject to similar enforcement.
5.0 Behavior of Rows Outside the Filter Rows that fall outside of the filter set on a FilteredRowSet object cannot be modified until the filter is removed or a new filter is applied.
Furthermore, only rows that fall within the bounds of a filter will be synchronized with the data source.
The standard interface that all standard implementations of FilteredRowSet must implement. The FilteredRowSetImpl 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. 1.0 Background There are occasions when a RowSet 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 RowSet implementations; however, this is an impractical approach for lightweight components such as disconnected RowSet objects. The FilteredRowSet interface seeks to address this need without supplying a heavyweight query language along with the processing that such a query language would require. A JDBC FilteredRowSet standard implementation implements the RowSet interfaces and extends the CachedRowSet™ class. The CachedRowSet class provides a set of protected cursor manipulation methods, which a FilteredRowSet implementation can override to supply filtering support. 2.0 Predicate Sharing If a FilteredRowSet implementation is shared using the inherited createShared method in parent interfaces, the Predicate should be shared without modification by all FilteredRowSet instance clones. 3.0 Usage By implementing a Predicate (see example in Predicate class JavaDoc), a FilteredRowSet could then be used as described below. 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 In the example above, we initialize a Range object which implements the Predicate interface. This object expresses the following constraints: All rows outputted or modified from this FilteredRowSet object must fall between the values 'Alpha' and 'Bravo' both values inclusive, in the column 'columnName'. If a filter is applied to a FilteredRowSet object that contains no data that falls within the range of the filter, no rows are returned. 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. 4.0 Updating a FilteredRowSet Object The predicate set on a FilteredRowSet object applies a criterion on all rows in a RowSet object to manage a subset of rows in a RowSet object. This criterion governs the subset of rows that are visible and also defines which rows can be modified, deleted or inserted. Therefore, the predicate set on a FilteredRowSet object must be considered as bi-directional and the set criterion as the gating mechanism for all views and updates to the FilteredRowSet object. Any attempt to update the FilteredRowSet that violates the criterion will result in a SQLException object being thrown. The FilteredRowSet range criterion can be modified by applying a new Predicate object to the FilteredRowSet instance at any time. This is possible if no additional references to the FilteredRowSet object are detected. A new filter has has an immediate effect on criterion enforcement within the FilteredRowSet object, and all subsequent views and updates will be subject to similar enforcement. 5.0 Behavior of Rows Outside the Filter Rows that fall outside of the filter set on a FilteredRowSet object cannot be modified until the filter is removed or a new filter is applied. Furthermore, only rows that fall within the bounds of a filter will be synchronized with the data source.
The standard interface that all standard implementations of JdbcRowSet must implement.
1.0 Overview A wrapper around a ResultSet object that makes it possible to use the result set as a JavaBeans™ component. Thus, a JdbcRowSet object can be one of the Beans that a tool makes available for composing an application. Because a JdbcRowSet 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.
Because it is always connected to its database, an instance of JdbcRowSet can simply take calls invoked on it and in turn call them on its ResultSet object. As a consequence, a result set can, for example, be a component in a Swing application.
Another advantage of a JdbcRowSet object is that it can be used to make a ResultSet object scrollable and updatable. All RowSet 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 JdbcRowSet object with the data of a ResultSet object and then operate on the JdbcRowSet object as if it were the ResultSet object.
2.0 Creating a JdbcRowSet Object The reference implementation of the JdbcRowSet interface, JdbcRowSetImpl, 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 execute method is called. In general, this method does the following:
establishes a connection with a database creates a PreparedStatement object and sets any of its placeholder parameters executes the statement to create a ResultSet object
If the execute method is successful, it will set the appropriate private JdbcRowSet fields with the following:
a Connection object -- the connection between the rowset and the database a PreparedStatement object -- the query that produces the result set a ResultSet object -- the result set that the rowset's command produced and that is being made, in effect, a JavaBeans component
If these fields have not been set, meaning that the execute method has not executed successfully, no methods other than execute and close may be called on the rowset. All other public methods will throw an exception.
Before calling the execute method, however, the command and properties needed for establishing a connection must be set. The following code fragment creates a JdbcRowSetImpl object, sets the command and connection properties, sets the placeholder parameter, and then invokes the method execute.
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();
The variable jrs now represents an instance of JdbcRowSetImpl that is a thin wrapper around the ResultSet object containing all the rows in the table TITLES where the type of book is biography. At this point, operations called on jrs will affect the rows in the result set, which is effectively a JavaBeans component.
The implementation of the RowSet method execute in the JdbcRowSet reference implementation differs from that in the CachedRowSet™ reference implementation to account for the different requirements of connected and disconnected RowSet objects.
The standard interface that all standard implementations of JdbcRowSet must implement. 1.0 Overview A wrapper around a ResultSet object that makes it possible to use the result set as a JavaBeans™ component. Thus, a JdbcRowSet object can be one of the Beans that a tool makes available for composing an application. Because a JdbcRowSet 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. Because it is always connected to its database, an instance of JdbcRowSet can simply take calls invoked on it and in turn call them on its ResultSet object. As a consequence, a result set can, for example, be a component in a Swing application. Another advantage of a JdbcRowSet object is that it can be used to make a ResultSet object scrollable and updatable. All RowSet 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 JdbcRowSet object with the data of a ResultSet object and then operate on the JdbcRowSet object as if it were the ResultSet object. 2.0 Creating a JdbcRowSet Object The reference implementation of the JdbcRowSet interface, JdbcRowSetImpl, 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 execute method is called. In general, this method does the following: establishes a connection with a database creates a PreparedStatement object and sets any of its placeholder parameters executes the statement to create a ResultSet object If the execute method is successful, it will set the appropriate private JdbcRowSet fields with the following: a Connection object -- the connection between the rowset and the database a PreparedStatement object -- the query that produces the result set a ResultSet object -- the result set that the rowset's command produced and that is being made, in effect, a JavaBeans component If these fields have not been set, meaning that the execute method has not executed successfully, no methods other than execute and close may be called on the rowset. All other public methods will throw an exception. Before calling the execute method, however, the command and properties needed for establishing a connection must be set. The following code fragment creates a JdbcRowSetImpl object, sets the command and connection properties, sets the placeholder parameter, and then invokes the method execute. 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(); The variable jrs now represents an instance of JdbcRowSetImpl that is a thin wrapper around the ResultSet object containing all the rows in the table TITLES where the type of book is biography. At this point, operations called on jrs will affect the rows in the result set, which is effectively a JavaBeans component. The implementation of the RowSet method execute in the JdbcRowSet reference implementation differs from that in the CachedRowSet™ reference implementation to account for the different requirements of connected and disconnected RowSet objects.
1.0 Background The Joinable interface provides the methods for getting and setting a match column, which is the basis for forming the SQL JOIN formed by adding RowSet objects to a JoinRowSet object.
Any standard RowSet implementation may implement the Joinable interface in order to be added to a JoinRowSet object. Implementing this interface gives a RowSet object the ability to use Joinable methods, which set, retrieve, and get information about match columns. An application may add a RowSet object that has not implemented the Joinable interface to a JoinRowSet object, but to do so it must use one of the JoinRowSet.addRowSet methods that takes both a RowSet object and a match column or an array of RowSet objects and an array of match columns.
To get access to the methods in the Joinable interface, a RowSet object implements at least one of the five standard RowSet interfaces and also implements the Joinable interface. In addition, most RowSet objects extend the BaseRowSet class. For example:
class MyRowSetImpl extends BaseRowSet implements CachedRowSet, Joinable {
:
:
}
2.0 Usage Guidelines
The methods in the Joinable interface allow a RowSet object to set a match column, retrieve a match column, or unset a match column, which is the column upon which an SQL JOIN can be based. An instance of a class that implements these methods can be added to a JoinRowSet object to allow an SQL JOIN relationship to be established.
CachedRowSet crs = new MyRowSetImpl();
crs.populate((ResultSet)rs);
(Joinable)crs.setMatchColumnIndex(1);
JoinRowSet jrs = new JoinRowSetImpl();
jrs.addRowSet(crs);
In the previous example, crs is a CachedRowSet object that has implemented the Joinable interface. In the following example, crs2 has not, so it must supply the match column as an argument to the addRowSet method. This example assumes that column 1 is the match column.
CachedRowSet crs2 = new MyRowSetImpl();
crs2.populate((ResultSet)rs);
JoinRowSet jrs2 = new JoinRowSetImpl();
jrs2.addRowSet(crs2, 1);
The JoinRowSet interface makes it possible to get data from one or more RowSet 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 RowSet objects. Nevertheless, any RowSet object may implement this interface regardless of whether it is connected or disconnected. Note that a JdbcRowSet object, being always connected to its data source, can become part of an SQL JOIN directly without having to become part of a JoinRowSet object.
3.0 Managing Multiple Match Columns The index array passed into the setMatchColumn 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:
int[] i = {1, 2, 4, 7}; // indicates four match columns, with column
// indexes 1, 2, 4, 7 participating in the JOIN.
Joinable.setMatchColumn(i);
Subsequent match columns may be added as follows to a different Joinable object (a RowSet object that has implemented the Joinable interface).
int[] w = {3, 2, 5, 3};
Joinable2.setMatchColumn(w);
When an application adds two or more RowSet objects to a JoinRowSet 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 RowSet object. If overlap or underlap occurs, the match column data is maintained in the event an additional Joinable 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 SQL JOIN.
This assertion applies in exactly the same manner when column names are used rather than column indexes to indicate match columns.
1.0 Background The Joinable interface provides the methods for getting and setting a match column, which is the basis for forming the SQL JOIN formed by adding RowSet objects to a JoinRowSet object. Any standard RowSet implementation may implement the Joinable interface in order to be added to a JoinRowSet object. Implementing this interface gives a RowSet object the ability to use Joinable methods, which set, retrieve, and get information about match columns. An application may add a RowSet object that has not implemented the Joinable interface to a JoinRowSet object, but to do so it must use one of the JoinRowSet.addRowSet methods that takes both a RowSet object and a match column or an array of RowSet objects and an array of match columns. To get access to the methods in the Joinable interface, a RowSet object implements at least one of the five standard RowSet interfaces and also implements the Joinable interface. In addition, most RowSet objects extend the BaseRowSet class. For example: class MyRowSetImpl extends BaseRowSet implements CachedRowSet, Joinable { : : } 2.0 Usage Guidelines The methods in the Joinable interface allow a RowSet object to set a match column, retrieve a match column, or unset a match column, which is the column upon which an SQL JOIN can be based. An instance of a class that implements these methods can be added to a JoinRowSet object to allow an SQL JOIN relationship to be established. CachedRowSet crs = new MyRowSetImpl(); crs.populate((ResultSet)rs); (Joinable)crs.setMatchColumnIndex(1); JoinRowSet jrs = new JoinRowSetImpl(); jrs.addRowSet(crs); In the previous example, crs is a CachedRowSet object that has implemented the Joinable interface. In the following example, crs2 has not, so it must supply the match column as an argument to the addRowSet method. This example assumes that column 1 is the match column. CachedRowSet crs2 = new MyRowSetImpl(); crs2.populate((ResultSet)rs); JoinRowSet jrs2 = new JoinRowSetImpl(); jrs2.addRowSet(crs2, 1); The JoinRowSet interface makes it possible to get data from one or more RowSet 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 RowSet objects. Nevertheless, any RowSet object may implement this interface regardless of whether it is connected or disconnected. Note that a JdbcRowSet object, being always connected to its data source, can become part of an SQL JOIN directly without having to become part of a JoinRowSet object. 3.0 Managing Multiple Match Columns The index array passed into the setMatchColumn 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: int[] i = {1, 2, 4, 7}; // indicates four match columns, with column // indexes 1, 2, 4, 7 participating in the JOIN. Joinable.setMatchColumn(i); Subsequent match columns may be added as follows to a different Joinable object (a RowSet object that has implemented the Joinable interface). int[] w = {3, 2, 5, 3}; Joinable2.setMatchColumn(w); When an application adds two or more RowSet objects to a JoinRowSet 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 RowSet object. If overlap or underlap occurs, the match column data is maintained in the event an additional Joinable 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 SQL JOIN. This assertion applies in exactly the same manner when column names are used rather than column indexes to indicate match columns.
The JoinRowSet interface provides a mechanism for combining related data from different RowSet objects into one JoinRowSet object, which represents an SQL JOIN. In other words, a JoinRowSet object acts as a container for the data from RowSet objects that form an SQL JOIN relationship.
The Joinable interface provides the methods for setting, retrieving, and unsetting a match column, the basis for establishing an SQL JOIN relationship. The match column may alternatively be set by supplying it to the appropriate version of the JointRowSet method addRowSet.
1.0 Overview Disconnected RowSet objects (CachedRowSet objects and implementations extending the CachedRowSet interface) do not have a standard way to establish an SQL JOIN between RowSet objects without the expensive operation of reconnecting to the data source. The JoinRowSet interface is specifically designed to address this need.
Any RowSet object can be added to a JoinRowSet object to become part of an SQL JOIN relationship. This means that both connected and disconnected RowSet objects can be part of a JOIN. RowSet objects operating in a connected environment (JdbcRowSet objects) are encouraged to use the database to which they are already connected to establish SQL JOIN relationships between tables directly. However, it is possible for a JdbcRowSet object to be added to a JoinRowSet object if necessary.
Any number of RowSet objects can be added to an instance of JoinRowSet provided that they can be related in an SQL JOIN. By definition, the SQL JOIN statement is used to combine the data contained in two or more relational database tables based upon a common attribute. The Joinable interface provides the methods for establishing a common attribute, which is done by setting a match column. 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 JoinRowSet object establishes JOIN relationships between RowSet objects without the assistance of an available relational database.
The type of JOIN to be established is determined by setting one of the JoinRowSet constants using the method setJoinType. The following SQL JOIN types can be set:
CROSS_JOIN FULL_JOIN INNER_JOIN - the default if no JOIN type has been set LEFT_OUTER_JOIN RIGHT_OUTER_JOIN
Note that if no type is set, the JOIN will automatically be an inner join. The comments for the fields in the JoinRowSet interface explain these JOIN types, which are standard SQL JOIN types.
2.0 Using a JoinRowSet Object for Creating a JOIN When a JoinRowSet object is created, it is empty. The first RowSet object to be added becomes the basis for the JOIN relationship. Applications must determine which column in each of the RowSet objects to be added to the JoinRowSet object should be the match column. All of the RowSet 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.
A match column can be be set in two ways:
By calling the Joinable method setMatchColumn This is the only method that can set the match column before a RowSet object is added to a JoinRowSet object. The RowSet object must have implemented the Joinable interface in order to use the method setMatchColumn. Once the match column value has been set, this method can be used to reset the match column at any time. By calling one of the versions of the JoinRowSet method addRowSet that takes a column name or number (or an array of column names or numbers) Four of the five addRowSet methods take a match column as a parameter. These four methods set or reset the match column at the time a RowSet object is being added to a JoinRowSet object.
3.0 Sample Usage
The following code fragment adds two CachedRowSet objects to a JoinRowSet object. Note that in this example, no SQL JOIN type is set, so the default JOIN type, which is INNER_JOIN, is established.
In the following code fragment, the table EMPLOYEES, whose match column is set to the first column (EMP_ID), is added to the JoinRowSet object jrs. Then the table ESSP_BONUS_PLAN, whose match column is likewise the EMP_ID column, is added. When this second table is added to jrs, only the rows in ESSP_BONUS_PLAN whose EMP_ID value matches an EMP_ID value in the EMPLOYEES table are added. In this case, everyone in the bonus plan is an employee, so all of the rows in the table ESSP_BONUS_PLAN are added to the JoinRowSet object. In this example, both CachedRowSet objects being added have implemented the Joinable interface and can therefore call the Joinable method setMatchColumn.
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);
At this point, jrs is an inside JOIN of the two RowSet objects based on their EMP_ID columns. The application can now browse the combined data as if it were browsing one single RowSet object. Because jrs is itself a RowSet object, an application can navigate or modify it using RowSet methods.
jrs.first();
int employeeID = jrs.getInt(1);
String employeeName = jrs.getString(2);
Note that because the SQL JOIN must be enforced when an application adds a second or subsequent RowSet object, there may be an initial degradation in performance while the JOIN is being performed.
The following code fragment adds an additional CachedRowSet object. In this case, the match column (EMP_ID) is set when the CachedRowSet object is added to the JoinRowSet object.
ResultSet rs3 = stmt.executeQuery(`SELECT * FROM 401K_CONTRIB`);
CachedRowSet fourO1k = new CachedRowSetImpl();
four01k.populate(rs3);
jrs.addRowSet(four01k, 1);
The JoinRowSet object jrs now contains values from all three tables. The data in each row in four01k in which the value for the EMP_ID column matches a value for the EMP_ID column in jrs has been added to jrs.
4.0 JoinRowSet Methods The JoinRowSet interface supplies several methods for adding RowSet objects and for getting information about the JoinRowSet object.
Methods for adding one or more RowSet objects These methods allow an application to add one RowSet object at a time or to add multiple RowSet objects at one time. In either case, the methods may specify the match column for each RowSet object being added. Methods for getting information One method retrieves the RowSet objects in the JoinRowSet object, and another method retrieves the RowSet names. A third method retrieves either the SQL WHERE clause used behind the scenes to form the JOIN or a text description of what the WHERE clause does. Methods related to the type of JOIN One method sets the JOIN type, and five methods find out whether the JoinRowSet object supports a given type. A method to make a separate copy of the JoinRowSet object This method creates a copy that can be persisted to the data source.
The JoinRowSet interface provides a mechanism for combining related data from different RowSet objects into one JoinRowSet object, which represents an SQL JOIN. In other words, a JoinRowSet object acts as a container for the data from RowSet objects that form an SQL JOIN relationship. The Joinable interface provides the methods for setting, retrieving, and unsetting a match column, the basis for establishing an SQL JOIN relationship. The match column may alternatively be set by supplying it to the appropriate version of the JointRowSet method addRowSet. 1.0 Overview Disconnected RowSet objects (CachedRowSet objects and implementations extending the CachedRowSet interface) do not have a standard way to establish an SQL JOIN between RowSet objects without the expensive operation of reconnecting to the data source. The JoinRowSet interface is specifically designed to address this need. Any RowSet object can be added to a JoinRowSet object to become part of an SQL JOIN relationship. This means that both connected and disconnected RowSet objects can be part of a JOIN. RowSet objects operating in a connected environment (JdbcRowSet objects) are encouraged to use the database to which they are already connected to establish SQL JOIN relationships between tables directly. However, it is possible for a JdbcRowSet object to be added to a JoinRowSet object if necessary. Any number of RowSet objects can be added to an instance of JoinRowSet provided that they can be related in an SQL JOIN. By definition, the SQL JOIN statement is used to combine the data contained in two or more relational database tables based upon a common attribute. The Joinable interface provides the methods for establishing a common attribute, which is done by setting a match column. 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 JoinRowSet object establishes JOIN relationships between RowSet objects without the assistance of an available relational database. The type of JOIN to be established is determined by setting one of the JoinRowSet constants using the method setJoinType. The following SQL JOIN types can be set: CROSS_JOIN FULL_JOIN INNER_JOIN - the default if no JOIN type has been set LEFT_OUTER_JOIN RIGHT_OUTER_JOIN Note that if no type is set, the JOIN will automatically be an inner join. The comments for the fields in the JoinRowSet interface explain these JOIN types, which are standard SQL JOIN types. 2.0 Using a JoinRowSet Object for Creating a JOIN When a JoinRowSet object is created, it is empty. The first RowSet object to be added becomes the basis for the JOIN relationship. Applications must determine which column in each of the RowSet objects to be added to the JoinRowSet object should be the match column. All of the RowSet 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. A match column can be be set in two ways: By calling the Joinable method setMatchColumn This is the only method that can set the match column before a RowSet object is added to a JoinRowSet object. The RowSet object must have implemented the Joinable interface in order to use the method setMatchColumn. Once the match column value has been set, this method can be used to reset the match column at any time. By calling one of the versions of the JoinRowSet method addRowSet that takes a column name or number (or an array of column names or numbers) Four of the five addRowSet methods take a match column as a parameter. These four methods set or reset the match column at the time a RowSet object is being added to a JoinRowSet object. 3.0 Sample Usage The following code fragment adds two CachedRowSet objects to a JoinRowSet object. Note that in this example, no SQL JOIN type is set, so the default JOIN type, which is INNER_JOIN, is established. In the following code fragment, the table EMPLOYEES, whose match column is set to the first column (EMP_ID), is added to the JoinRowSet object jrs. Then the table ESSP_BONUS_PLAN, whose match column is likewise the EMP_ID column, is added. When this second table is added to jrs, only the rows in ESSP_BONUS_PLAN whose EMP_ID value matches an EMP_ID value in the EMPLOYEES table are added. In this case, everyone in the bonus plan is an employee, so all of the rows in the table ESSP_BONUS_PLAN are added to the JoinRowSet object. In this example, both CachedRowSet objects being added have implemented the Joinable interface and can therefore call the Joinable method setMatchColumn. 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); At this point, jrs is an inside JOIN of the two RowSet objects based on their EMP_ID columns. The application can now browse the combined data as if it were browsing one single RowSet object. Because jrs is itself a RowSet object, an application can navigate or modify it using RowSet methods. jrs.first(); int employeeID = jrs.getInt(1); String employeeName = jrs.getString(2); Note that because the SQL JOIN must be enforced when an application adds a second or subsequent RowSet object, there may be an initial degradation in performance while the JOIN is being performed. The following code fragment adds an additional CachedRowSet object. In this case, the match column (EMP_ID) is set when the CachedRowSet object is added to the JoinRowSet object. ResultSet rs3 = stmt.executeQuery(`SELECT * FROM 401K_CONTRIB`); CachedRowSet fourO1k = new CachedRowSetImpl(); four01k.populate(rs3); jrs.addRowSet(four01k, 1); The JoinRowSet object jrs now contains values from all three tables. The data in each row in four01k in which the value for the EMP_ID column matches a value for the EMP_ID column in jrs has been added to jrs. 4.0 JoinRowSet Methods The JoinRowSet interface supplies several methods for adding RowSet objects and for getting information about the JoinRowSet object. Methods for adding one or more RowSet objects These methods allow an application to add one RowSet object at a time or to add multiple RowSet objects at one time. In either case, the methods may specify the match column for each RowSet object being added. Methods for getting information One method retrieves the RowSet objects in the JoinRowSet object, and another method retrieves the RowSet names. A third method retrieves either the SQL WHERE clause used behind the scenes to form the JOIN or a text description of what the WHERE clause does. Methods related to the type of JOIN One method sets the JOIN type, and five methods find out whether the JoinRowSet object supports a given type. A method to make a separate copy of the JoinRowSet object This method creates a copy that can be persisted to the data source.
The standard interface that provides the framework for all FilteredRowSet objects to describe their filters.
1.0 Background The Predicate interface is a standard interface that applications can implement to define the filter they wish to apply to a a FilteredRowSet object. A FilteredRowSet object consumes implementations of this interface and enforces the constraints defined in the implementation of the method evaluate. A FilteredRowSet 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.
2.0 Implementation Guidelines In order to supply a predicate for the FilteredRowSet. 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 FilteredRowSet interface, this allows for a flexible and application motivated implementations of Predicate to emerge.
A sample implementation would look something like this:
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;
}
}
The example above implements a simple range predicate. Note, that implementations should but are not required to provide String and integer index based constructors to provide for JDBC RowSet Implementation applications that use both column identification conventions.
The standard interface that provides the framework for all FilteredRowSet objects to describe their filters. 1.0 Background The Predicate interface is a standard interface that applications can implement to define the filter they wish to apply to a a FilteredRowSet object. A FilteredRowSet object consumes implementations of this interface and enforces the constraints defined in the implementation of the method evaluate. A FilteredRowSet 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. 2.0 Implementation Guidelines In order to supply a predicate for the FilteredRowSet. 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 FilteredRowSet interface, this allows for a flexible and application motivated implementations of Predicate to emerge. A sample implementation would look something like this: 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; } } The example above implements a simple range predicate. Note, that implementations should but are not required to provide String and integer index based constructors to provide for JDBC RowSet Implementation applications that use both column identification conventions.
An interface that defines the implementation of a factory that is used to obtain different types of RowSet implementations.
An interface that defines the implementation of a factory that is used to obtain different types of RowSet implementations.
Provides implementations for the methods that set and get metadata information about a RowSet object's columns. A RowSetMetaDataImpl object keeps track of the number of columns in the rowset and maintains an internal array of column attributes for each column.
A RowSet object creates a RowSetMetaDataImpl object internally in order to set and retrieve information about its columns.
NOTE: All metadata in a RowSetMetaDataImpl object should be considered as unavailable until the RowSet object that it describes is populated. Therefore, any RowSetMetaDataImpl method that retrieves information is defined as having unspecified behavior when it is called before the RowSet object contains data.
Provides implementations for the methods that set and get metadata information about a RowSet object's columns. A RowSetMetaDataImpl object keeps track of the number of columns in the rowset and maintains an internal array of column attributes for each column. A RowSet object creates a RowSetMetaDataImpl object internally in order to set and retrieve information about its columns. NOTE: All metadata in a RowSetMetaDataImpl object should be considered as unavailable until the RowSet object that it describes is populated. Therefore, any RowSetMetaDataImpl method that retrieves information is defined as having unspecified behavior when it is called before the RowSet object contains data.
A factory API that enables applications to obtain a RowSetFactory implementation that can be used to create different types of RowSet implementations.
Example:
RowSetFactory aFactory = RowSetProvider.newFactory();
CachedRowSet crs = aFactory.createCachedRowSet();
...
RowSetFactory rsf = RowSetProvider.newFactory(com.sun.rowset.RowSetFactoryImpl
, null);
WebRowSet wrs = rsf.createWebRowSet();
Tracing of this class may be enabled by setting the System property javax.sql.rowset.RowSetFactory.debug to any value but false.
A factory API that enables applications to obtain a RowSetFactory implementation that can be used to create different types of RowSet implementations. Example: RowSetFactory aFactory = RowSetProvider.newFactory(); CachedRowSet crs = aFactory.createCachedRowSet(); ... RowSetFactory rsf = RowSetProvider.newFactory(`com.sun.rowset.RowSetFactoryImpl`, null); WebRowSet wrs = rsf.createWebRowSet(); Tracing of this class may be enabled by setting the System property javax.sql.rowset.RowSetFactory.debug to any value but false.
An extension of SQLException that provides information about database warnings set on RowSet objects. Warnings are silently chained to the object whose method call caused it to be reported. This class complements the SQLWarning class.
Rowset warnings may be retrieved from JdbcRowSet, CachedRowSet™, WebRowSet, FilteredRowSet, or JoinRowSet implementations. To retrieve the first warning reported on any RowSet implementation, use the method getRowSetWarnings defined in the JdbcRowSet interface or the CachedRowSet interface. To retrieve a warning chained to the first warning, use the RowSetWarning method getNextWarning. To retrieve subsequent warnings, call getNextWarning on each RowSetWarning object that is returned.
The inherited methods getMessage, getSQLState, and getErrorCode retrieve information contained in a RowSetWarning object.
An extension of SQLException that provides information about database warnings set on RowSet objects. Warnings are silently chained to the object whose method call caused it to be reported. This class complements the SQLWarning class. Rowset warnings may be retrieved from JdbcRowSet, CachedRowSet™, WebRowSet, FilteredRowSet, or JoinRowSet implementations. To retrieve the first warning reported on any RowSet implementation, use the method getRowSetWarnings defined in the JdbcRowSet interface or the CachedRowSet interface. To retrieve a warning chained to the first warning, use the RowSetWarning method getNextWarning. To retrieve subsequent warnings, call getNextWarning on each RowSetWarning object that is returned. The inherited methods getMessage, getSQLState, and getErrorCode retrieve information contained in a RowSetWarning object.
No vars found in this namespace.
A serialized version of an Array object, which is the mapping in the Java programming language of an SQL ARRAY value.
The SerialArray class provides a constructor for creating a SerialArray instance from an Array object, methods for getting the base type and the SQL name for the base type, and methods for copying all or part of a SerialArray object.
Note: In order for this class to function correctly, a connection to the data source must be available in order for the SQL Array object to be materialized (have all of its elements brought to the client server) if necessary. At this time, logical pointers to the data in the data source, such as locators, are not currently supported.
Thread safety
A SerialArray is not safe for use by multiple concurrent threads. If a SerialArray is to be used by more than one thread then access to the SerialArray should be controlled by appropriate synchronization.
A serialized version of an Array object, which is the mapping in the Java programming language of an SQL ARRAY value. The SerialArray class provides a constructor for creating a SerialArray instance from an Array object, methods for getting the base type and the SQL name for the base type, and methods for copying all or part of a SerialArray object. Note: In order for this class to function correctly, a connection to the data source must be available in order for the SQL Array object to be materialized (have all of its elements brought to the client server) if necessary. At this time, logical pointers to the data in the data source, such as locators, are not currently supported. Thread safety A SerialArray is not safe for use by multiple concurrent threads. If a SerialArray is to be used by more than one thread then access to the SerialArray should be controlled by appropriate synchronization.
A serialized mapping in the Java programming language of an SQL BLOB value.
The SerialBlob class provides a constructor for creating an instance from a Blob object. Note that the Blob object should have brought the SQL BLOB value's data over to the client before a SerialBlob object is constructed from it. The data of an SQL BLOB value can be materialized on the client as an array of bytes (using the method Blob.getBytes) or as a stream of uninterpreted bytes (using the method Blob.getBinaryStream).
SerialBlob methods make it possible to make a copy of a SerialBlob object as an array of bytes or as a stream. They also make it possible to locate a given pattern of bytes or a Blob object within a SerialBlob object and to update or truncate a Blob object.
Thread safety
A SerialBlob is not safe for use by multiple concurrent threads. If a SerialBlob is to be used by more than one thread then access to the SerialBlob should be controlled by appropriate synchronization.
A serialized mapping in the Java programming language of an SQL BLOB value. The SerialBlob class provides a constructor for creating an instance from a Blob object. Note that the Blob object should have brought the SQL BLOB value's data over to the client before a SerialBlob object is constructed from it. The data of an SQL BLOB value can be materialized on the client as an array of bytes (using the method Blob.getBytes) or as a stream of uninterpreted bytes (using the method Blob.getBinaryStream). SerialBlob methods make it possible to make a copy of a SerialBlob object as an array of bytes or as a stream. They also make it possible to locate a given pattern of bytes or a Blob object within a SerialBlob object and to update or truncate a Blob object. Thread safety A SerialBlob is not safe for use by multiple concurrent threads. If a SerialBlob is to be used by more than one thread then access to the SerialBlob should be controlled by appropriate synchronization.
A serialized mapping in the Java programming language of an SQL CLOB value.
The SerialClob class provides a constructor for creating an instance from a Clob object. Note that the Clob object should have brought the SQL CLOB value's data over to the client before a SerialClob object is constructed from it. The data of an SQL CLOB value can be materialized on the client as a stream of Unicode characters.
SerialClob methods make it possible to get a substring from a SerialClob object or to locate the start of a pattern of characters.
Thread safety
A SerialClob is not safe for use by multiple concurrent threads. If a SerialClob is to be used by more than one thread then access to the SerialClob should be controlled by appropriate synchronization.
A serialized mapping in the Java programming language of an SQL CLOB value. The SerialClob class provides a constructor for creating an instance from a Clob object. Note that the Clob object should have brought the SQL CLOB value's data over to the client before a SerialClob object is constructed from it. The data of an SQL CLOB value can be materialized on the client as a stream of Unicode characters. SerialClob methods make it possible to get a substring from a SerialClob object or to locate the start of a pattern of characters. Thread safety A SerialClob is not safe for use by multiple concurrent threads. If a SerialClob is to be used by more than one thread then access to the SerialClob should be controlled by appropriate synchronization.
A serialized mapping in the Java programming language of an SQL DATALINK value. A DATALINK value references a file outside of the underlying data source that the data source manages.
RowSet implementations can use the method RowSet.getURL to retrieve a java.net.URL object, which can be used to manipulate the external data.
java.net.URL url = rowset.getURL(1);
Thread safety
A SerialDatalink is not safe for use by multiple concurrent threads. If a SerialDatalink is to be used by more than one thread then access to the SerialDatalink should be controlled by appropriate synchronization.
A serialized mapping in the Java programming language of an SQL DATALINK value. A DATALINK value references a file outside of the underlying data source that the data source manages. RowSet implementations can use the method RowSet.getURL to retrieve a java.net.URL object, which can be used to manipulate the external data. java.net.URL url = rowset.getURL(1); Thread safety A SerialDatalink is not safe for use by multiple concurrent threads. If a SerialDatalink is to be used by more than one thread then access to the SerialDatalink should be controlled by appropriate synchronization.
Indicates and an error with the serialization or de-serialization of SQL types such as BLOB, CLOB, STRUCT or ARRAY in addition to SQL types such as DATALINK and JAVAOBJECT
Indicates and an error with the serialization or de-serialization of SQL types such as BLOB, CLOB, STRUCT or ARRAY in addition to SQL types such as DATALINK and JAVAOBJECT
A serializable mapping in the Java programming language of an SQL JAVA_OBJECT value. Assuming the Java object implements the Serializable interface, this class simply wraps the serialization process.
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 SerialException object being thrown.
Thread safety
A SerialJavaObject is not safe for use by multiple concurrent threads. If a SerialJavaObject is to be used by more than one thread then access to the SerialJavaObject should be controlled by appropriate synchronization.
A serializable mapping in the Java programming language of an SQL JAVA_OBJECT value. Assuming the Java object implements the Serializable interface, this class simply wraps the serialization process. 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 SerialException object being thrown. Thread safety A SerialJavaObject is not safe for use by multiple concurrent threads. If a SerialJavaObject is to be used by more than one thread then access to the SerialJavaObject should be controlled by appropriate synchronization.
A serialized mapping of a Ref object, which is the mapping in the Java programming language of an SQL REF value.
The SerialRef class provides a constructor for creating a SerialRef instance from a Ref object and provides methods for getting and setting the Ref object.
Thread safety
A SerialRef is not safe for use by multiple concurrent threads. If a SerialRef is to be used by more than one thread then access to the SerialRef should be controlled by appropriate synchronization.
A serialized mapping of a Ref object, which is the mapping in the Java programming language of an SQL REF value. The SerialRef class provides a constructor for creating a SerialRef instance from a Ref object and provides methods for getting and setting the Ref object. Thread safety A SerialRef is not safe for use by multiple concurrent threads. If a SerialRef is to be used by more than one thread then access to the SerialRef should be controlled by appropriate synchronization.
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.
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.
The SerialStruct class provides a constructor for creating an instance from a Struct object, a method for retrieving the SQL type name of the SQL structured type in the database, and methods for retrieving its attribute values.
Thread safety
A SerialStruct is not safe for use by multiple concurrent threads. If a SerialStruct is to be used by more than one thread then access to the SerialStruct should be controlled by appropriate synchronization.
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. 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. The SerialStruct class provides a constructor for creating an instance from a Struct object, a method for retrieving the SQL type name of the SQL structured type in the database, and methods for retrieving its attribute values. Thread safety A SerialStruct is not safe for use by multiple concurrent threads. If a SerialStruct is to be used by more than one thread then access to the SerialStruct should be controlled by appropriate synchronization.
An input stream used for custom mapping user-defined types (UDTs). An SQLInputImpl object is an input stream that contains a stream of values that are the attributes of a UDT.
This class is used by the driver behind the scenes when the method getObject is called on an SQL structured or distinct type that has a custom mapping; a programmer never invokes SQLInputImpl methods directly. They are provided here as a convenience for those who write RowSet implementations.
The SQLInputImpl class provides a set of reader methods analogous to the ResultSet getter methods. These methods make it possible to read the values in an SQLInputImpl object.
The method wasNull is used to determine whether the the last value read was SQL NULL. When the method getObject is called with an object of a class implementing the interface SQLData, the JDBC driver calls the method SQLData.getSQLType to determine the SQL type of the UDT being custom mapped. The driver creates an instance of SQLInputImpl, populating it with the attributes of the UDT. The driver then passes the input stream to the method SQLData.readSQL, which in turn calls the SQLInputImpl reader methods to read the attributes from the input stream.
An input stream used for custom mapping user-defined types (UDTs). An SQLInputImpl object is an input stream that contains a stream of values that are the attributes of a UDT. This class is used by the driver behind the scenes when the method getObject is called on an SQL structured or distinct type that has a custom mapping; a programmer never invokes SQLInputImpl methods directly. They are provided here as a convenience for those who write RowSet implementations. The SQLInputImpl class provides a set of reader methods analogous to the ResultSet getter methods. These methods make it possible to read the values in an SQLInputImpl object. The method wasNull is used to determine whether the the last value read was SQL NULL. When the method getObject is called with an object of a class implementing the interface SQLData, the JDBC driver calls the method SQLData.getSQLType to determine the SQL type of the UDT being custom mapped. The driver creates an instance of SQLInputImpl, populating it with the attributes of the UDT. The driver then passes the input stream to the method SQLData.readSQL, which in turn calls the SQLInputImpl reader methods to read the attributes from the input stream.
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.
When an application calls the method PreparedStatement.setObject, 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 Class object for the class that implements SQLData for this UDT. If the value to be written is an instance of SQLData, the driver will create an instance of SQLOutputImpl and pass it to the method SQLData.writeSQL. The method writeSQL in turn calls the appropriate SQLOutputImpl.writeXXX methods to write data from the SQLData object to the SQLOutputImpl output stream as the representation of an SQL user-defined type.
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. When an application calls the method PreparedStatement.setObject, 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 Class object for the class that implements SQLData for this UDT. If the value to be written is an instance of SQLData, the driver will create an instance of SQLOutputImpl and pass it to the method SQLData.writeSQL. The method writeSQL in turn calls the appropriate SQLOutputImpl.writeXXX methods to write data from the SQLData object to the SQLOutputImpl output stream as the representation of an SQL user-defined type.
No vars found in this namespace.
The Service Provider Interface (SPI) mechanism that generates SyncProvider instances to be used by disconnected RowSet objects. The SyncProvider instances in turn provide the javax.sql.RowSetReader object the RowSet object needs to populate itself with data and the javax.sql.RowSetWriter object it needs to propagate changes to its data back to the underlying data source.
Because the methods in the SyncFactory class are all static, there is only one SyncFactory object per Java VM at any one time. This ensures that there is a single source from which a RowSet implementation can obtain its SyncProvider implementation.
1.0 Overview The SyncFactory class provides an internal registry of available synchronization provider implementations (SyncProvider 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.
java.util.Enumeration e = SyncFactory.getRegisteredProviders();
All standard RowSet implementations must provide at least two providers:
an optimistic provider for use with a CachedRowSet implementation or an implementation derived from it an XML provider, which is used for reading and writing XML, such as with WebRowSet objects
Note that the JDBC RowSet Implementations include the SyncProvider implementations RIOptimisticProvider and RIXmlProvider, which satisfy this requirement.
The SyncFactory class provides accessor methods to assist applications in determining which synchronization providers are currently registered with the SyncFactory.
Other methods let RowSet persistence providers be registered or de-registered with the factory mechanism. This allows additional synchronization provider implementations to be made available to RowSet objects at run time.
Applications can apply a degree of filtering to determine the level of synchronization that a SyncProvider implementation offers. The following criteria determine whether a provider is made available to a RowSet object:
If a particular provider is specified by a RowSet object, and the SyncFactory does not contain a reference to this provider, a SyncFactoryException is thrown stating that the synchronization provider could not be found.
If a RowSet implementation is instantiated with a specified provider and the specified provider has been properly registered, the requested provider is supplied. Otherwise a SyncFactoryException is thrown.
If a RowSet object does not specify a SyncProvider implementation and no additional SyncProvider implementations are available, the reference implementation providers are supplied.
2.0 Registering SyncProvider Implementations
Both vendors and developers can register SyncProvider implementations using one of the following mechanisms.
Using the command line The name of the provider is supplied on the command line, which will add the provider to the system properties. For example:
-Drowset.provider.classname=com.fred.providers.HighAvailabilityProvider Using the Standard Properties File 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:
#Default JDBC RowSet sync providers listing
rowset.provider.classname.0=com.sun.rowset.providers.RIOptimisticProvider rowset.provider.vendor.0=Oracle Corporation rowset.provider.version.0=1.0
rowset.provider.classname.1=com.sun.rowset.providers.RIXMLProvider rowset.provider.vendor.1=Oracle Corporation rowset.provider.version.1=1.0 The SyncFactory checks this file and registers the SyncProvider implementations that it contains. A developer or vendor can add other implementations to this file. For example, here is a possible addition:
rowset.provider.classname.2=com.fred.providers.HighAvailabilityProvider
rowset.provider.vendor.2=Fred, Inc.
rowset.provider.version.2=1.0
Using a JNDI Context Available providers can be registered on a JNDI context, and the SyncFactory will attempt to load SyncProvider 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, MyProvider is being registered on a CosNaming namespace, which is the namespace used by J2EE resources.
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);
Next, an application will register the JNDI context with the SyncFactory instance. This allows the SyncFactory to browse within the JNDI context looking for SyncProvider implementations.
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); If a RowSet object attempts to obtain a MyProvider object, the SyncFactory 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 SyncFactory instance verifies that the requested provider is a valid extension of the SyncProvider abstract class and then gives it to the RowSet object. In the following code fragment, a new CachedRowSet object is created and initialized with env, which contains the binding to MyProvider.
Hashtable env = new Hashtable();
env.put(SyncFactory.ROWSET_SYNC_PROVIDER, com.fred.providers.MyProvider
);
CachedRowSet crs = new com.sun.rowset.CachedRowSetImpl(env);
Further details on these mechanisms are available in the
javax.sql.rowset.spi package specification.
The Service Provider Interface (SPI) mechanism that generates SyncProvider instances to be used by disconnected RowSet objects. The SyncProvider instances in turn provide the javax.sql.RowSetReader object the RowSet object needs to populate itself with data and the javax.sql.RowSetWriter object it needs to propagate changes to its data back to the underlying data source. Because the methods in the SyncFactory class are all static, there is only one SyncFactory object per Java VM at any one time. This ensures that there is a single source from which a RowSet implementation can obtain its SyncProvider implementation. 1.0 Overview The SyncFactory class provides an internal registry of available synchronization provider implementations (SyncProvider 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. java.util.Enumeration e = SyncFactory.getRegisteredProviders(); All standard RowSet implementations must provide at least two providers: an optimistic provider for use with a CachedRowSet implementation or an implementation derived from it an XML provider, which is used for reading and writing XML, such as with WebRowSet objects Note that the JDBC RowSet Implementations include the SyncProvider implementations RIOptimisticProvider and RIXmlProvider, which satisfy this requirement. The SyncFactory class provides accessor methods to assist applications in determining which synchronization providers are currently registered with the SyncFactory. Other methods let RowSet persistence providers be registered or de-registered with the factory mechanism. This allows additional synchronization provider implementations to be made available to RowSet objects at run time. Applications can apply a degree of filtering to determine the level of synchronization that a SyncProvider implementation offers. The following criteria determine whether a provider is made available to a RowSet object: If a particular provider is specified by a RowSet object, and the SyncFactory does not contain a reference to this provider, a SyncFactoryException is thrown stating that the synchronization provider could not be found. If a RowSet implementation is instantiated with a specified provider and the specified provider has been properly registered, the requested provider is supplied. Otherwise a SyncFactoryException is thrown. If a RowSet object does not specify a SyncProvider implementation and no additional SyncProvider implementations are available, the reference implementation providers are supplied. 2.0 Registering SyncProvider Implementations Both vendors and developers can register SyncProvider implementations using one of the following mechanisms. Using the command line The name of the provider is supplied on the command line, which will add the provider to the system properties. For example: -Drowset.provider.classname=com.fred.providers.HighAvailabilityProvider Using the Standard Properties File 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: #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 The SyncFactory checks this file and registers the SyncProvider implementations that it contains. A developer or vendor can add other implementations to this file. For example, here is a possible addition: rowset.provider.classname.2=com.fred.providers.HighAvailabilityProvider rowset.provider.vendor.2=Fred, Inc. rowset.provider.version.2=1.0 Using a JNDI Context Available providers can be registered on a JNDI context, and the SyncFactory will attempt to load SyncProvider 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, MyProvider is being registered on a CosNaming namespace, which is the namespace used by J2EE resources. 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); Next, an application will register the JNDI context with the SyncFactory instance. This allows the SyncFactory to browse within the JNDI context looking for SyncProvider implementations. 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); If a RowSet object attempts to obtain a MyProvider object, the SyncFactory 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 SyncFactory instance verifies that the requested provider is a valid extension of the SyncProvider abstract class and then gives it to the RowSet object. In the following code fragment, a new CachedRowSet object is created and initialized with env, which contains the binding to MyProvider. Hashtable env = new Hashtable(); env.put(SyncFactory.ROWSET_SYNC_PROVIDER, `com.fred.providers.MyProvider`); CachedRowSet crs = new com.sun.rowset.CachedRowSetImpl(env); Further details on these mechanisms are available in the javax.sql.rowset.spi package specification.
Indicates an error with SyncFactory mechanism. A disconnected RowSet implementation cannot be used without a SyncProvider being successfully instantiated
Indicates an error with SyncFactory mechanism. A disconnected RowSet implementation cannot be used without a SyncProvider being successfully instantiated
The synchronization mechanism that provides reader/writer capabilities for disconnected RowSet objects. A SyncProvider implementation is a class that extends the SyncProvider abstract class.
A SyncProvider implementation is identified by a unique ID, which is its fully qualified class name. This name must be registered with the SyncFactory SPI, thus making the implementation available to all RowSet implementations. The factory mechanism in the reference implementation uses this name to instantiate the implementation, which can then provide a RowSet object with its reader (a javax.sql.RowSetReader object) and its writer (a javax.sql.RowSetWriter object).
The Jdbc RowSet Implementations specification provides two reference implementations of the SyncProvider abstract class: RIOptimisticProvider and RIXMLProvider. The RIOptimisticProvider can set any RowSet implementation with a RowSetReader object and a RowSetWriter object. However, only the RIXMLProvider implementation can set an XmlReader object and an XmlWriter object. A WebRowSet object uses the XmlReader object to read data in XML format to populate itself with that data. It uses the XmlWriter object to write itself to a stream or java.io.Writer object in XML format.
1.0 Naming Convention for Implementations As a guide to naming SyncProvider implementations, the following should be noted:
The name for a SyncProvider implementation is its fully qualified class name. It is recommended that vendors supply a SyncProvider implementation in a package named providers.
For instance, if a vendor named Fred, Inc. offered a SyncProvider implementation, you could have the following:
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
The following line of code uses the fully qualified name to register this implementation with the SyncFactory static instance.
SyncFactory.registerProvider(
`com.fred.providers.HighAvailabilityProvider`);
The default SyncProvider object provided with the reference implementation uses the following name:
com.sun.rowset.providers.RIOptimisticProvider
A vendor can register a SyncProvider implementation class name with Oracle Corporation by sending email to jdbc@sun.com. Oracle will maintain a database listing the available SyncProvider implementations for use with compliant RowSet implementations. This database will be similar to the one already maintained to list available JDBC drivers.
Vendors should refer to the reference implementation synchronization providers for additional guidance on how to implement a new SyncProvider implementation.
2.0 How a RowSet Object Gets Its Provider
A disconnected Rowset object may get access to a SyncProvider object in one of the following two ways:
Using a constructor
CachedRowSet crs = new CachedRowSet(
`com.fred.providers.HighAvailabilitySyncProvider`);
Using the setSyncProvider method
CachedRowSet crs = new CachedRowSet();
crs.setSyncProvider(`com.fred.providers.HighAvailabilitySyncProvider`);
By default, the reference implementations of the RowSet synchronization providers are always available to the Java platform. If no other pluggable synchronization providers have been correctly registered, the SyncFactory will automatically generate an instance of the default SyncProvider reference implementation. Thus, in the preceding code fragment, if no implementation named com.fred.providers.HighAvailabilitySyncProvider has been registered with the SyncFactory instance, crs will be assigned the default provider in the reference implementation, which is com.sun.rowset.providers.RIOptimisticProvider.
3.0 Violations and Synchronization Issues If an update between a disconnected RowSet object and a data source violates the original query or the underlying data source constraints, this will result in undefined behavior for all disconnected RowSet implementations and their designated SyncProvider implementations. Not defining the behavior when such violations occur offers greater flexibility for a SyncProvider implementation to determine its own best course of action.
A SyncProvider 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 SyncProvider implementation, all SyncProvider objects must throw a SyncProviderException.
4.0 Updatable SQL VIEWs It is possible for any disconnected or connected RowSet object to be populated from an SQL query that is formulated originally from an SQL VIEW. 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 SyncProvider class provides two constants to indicate whether an implementation supports updating an SQL VIEW.
NONUPDATABLE_VIEW_SYNC - Indicates that a SyncProvider implementation does not support synchronization with an SQL VIEW as the underlying source of data for the RowSet object. UPDATABLE_VIEW_SYNC - Indicates that a SyncProvider implementation supports synchronization with an SQL VIEW as the underlying source of data.
The default is for a RowSet object not to be updatable if it was populated with data from an SQL VIEW.
5.0 SyncProvider Constants The SyncProvider class provides three sets of constants that are used as return values or parameters for SyncProvider methods. SyncProvider objects may be implemented to perform synchronization between a RowSet object and its underlying data source with varying degrees of of care. The first group of constants indicate how synchronization is handled. For example, GRADE_NONE indicates that a SyncProvider object will not take any care to see what data is valid and will simply write the RowSet data to the data source. GRADE_MODIFIED_AT_COMMIT 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.
Constants to indicate the synchronization grade of a SyncProvider object
SyncProvider.GRADE_NONE SyncProvider.GRADE_MODIFIED_AT_COMMIT SyncProvider.GRADE_CHECK_ALL_AT_COMMIT SyncProvider.GRADE_LOCK_WHEN_MODIFIED SyncProvider.GRADE_LOCK_WHEN_LOADED
Constants to indicate what locks are set on the data source
SyncProvider.DATASOURCE_NO_LOCK
SyncProvider.DATASOURCE_ROW_LOCK
SyncProvider.DATASOURCE_TABLE_LOCK
SyncProvider.DATASOURCE_DB_LOCK
Constants to indicate whether a SyncProvider object can perform updates to an SQL VIEW These constants are explained in the preceding section (4.0).
SyncProvider.UPDATABLE_VIEW_SYNC
SyncProvider.NONUPDATABLE_VIEW_SYNC
The synchronization mechanism that provides reader/writer capabilities for disconnected RowSet objects. A SyncProvider implementation is a class that extends the SyncProvider abstract class. A SyncProvider implementation is identified by a unique ID, which is its fully qualified class name. This name must be registered with the SyncFactory SPI, thus making the implementation available to all RowSet implementations. The factory mechanism in the reference implementation uses this name to instantiate the implementation, which can then provide a RowSet object with its reader (a javax.sql.RowSetReader object) and its writer (a javax.sql.RowSetWriter object). The Jdbc RowSet Implementations specification provides two reference implementations of the SyncProvider abstract class: RIOptimisticProvider and RIXMLProvider. The RIOptimisticProvider can set any RowSet implementation with a RowSetReader object and a RowSetWriter object. However, only the RIXMLProvider implementation can set an XmlReader object and an XmlWriter object. A WebRowSet object uses the XmlReader object to read data in XML format to populate itself with that data. It uses the XmlWriter object to write itself to a stream or java.io.Writer object in XML format. 1.0 Naming Convention for Implementations As a guide to naming SyncProvider implementations, the following should be noted: The name for a SyncProvider implementation is its fully qualified class name. It is recommended that vendors supply a SyncProvider implementation in a package named providers. For instance, if a vendor named Fred, Inc. offered a SyncProvider implementation, you could have the following: 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 The following line of code uses the fully qualified name to register this implementation with the SyncFactory static instance. SyncFactory.registerProvider( `com.fred.providers.HighAvailabilityProvider`); The default SyncProvider object provided with the reference implementation uses the following name: com.sun.rowset.providers.RIOptimisticProvider A vendor can register a SyncProvider implementation class name with Oracle Corporation by sending email to jdbc@sun.com. Oracle will maintain a database listing the available SyncProvider implementations for use with compliant RowSet implementations. This database will be similar to the one already maintained to list available JDBC drivers. Vendors should refer to the reference implementation synchronization providers for additional guidance on how to implement a new SyncProvider implementation. 2.0 How a RowSet Object Gets Its Provider A disconnected Rowset object may get access to a SyncProvider object in one of the following two ways: Using a constructor CachedRowSet crs = new CachedRowSet( `com.fred.providers.HighAvailabilitySyncProvider`); Using the setSyncProvider method CachedRowSet crs = new CachedRowSet(); crs.setSyncProvider(`com.fred.providers.HighAvailabilitySyncProvider`); By default, the reference implementations of the RowSet synchronization providers are always available to the Java platform. If no other pluggable synchronization providers have been correctly registered, the SyncFactory will automatically generate an instance of the default SyncProvider reference implementation. Thus, in the preceding code fragment, if no implementation named com.fred.providers.HighAvailabilitySyncProvider has been registered with the SyncFactory instance, crs will be assigned the default provider in the reference implementation, which is com.sun.rowset.providers.RIOptimisticProvider. 3.0 Violations and Synchronization Issues If an update between a disconnected RowSet object and a data source violates the original query or the underlying data source constraints, this will result in undefined behavior for all disconnected RowSet implementations and their designated SyncProvider implementations. Not defining the behavior when such violations occur offers greater flexibility for a SyncProvider implementation to determine its own best course of action. A SyncProvider 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 SyncProvider implementation, all SyncProvider objects must throw a SyncProviderException. 4.0 Updatable SQL VIEWs It is possible for any disconnected or connected RowSet object to be populated from an SQL query that is formulated originally from an SQL VIEW. 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 SyncProvider class provides two constants to indicate whether an implementation supports updating an SQL VIEW. NONUPDATABLE_VIEW_SYNC - Indicates that a SyncProvider implementation does not support synchronization with an SQL VIEW as the underlying source of data for the RowSet object. UPDATABLE_VIEW_SYNC - Indicates that a SyncProvider implementation supports synchronization with an SQL VIEW as the underlying source of data. The default is for a RowSet object not to be updatable if it was populated with data from an SQL VIEW. 5.0 SyncProvider Constants The SyncProvider class provides three sets of constants that are used as return values or parameters for SyncProvider methods. SyncProvider objects may be implemented to perform synchronization between a RowSet object and its underlying data source with varying degrees of of care. The first group of constants indicate how synchronization is handled. For example, GRADE_NONE indicates that a SyncProvider object will not take any care to see what data is valid and will simply write the RowSet data to the data source. GRADE_MODIFIED_AT_COMMIT 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. Constants to indicate the synchronization grade of a SyncProvider object SyncProvider.GRADE_NONE SyncProvider.GRADE_MODIFIED_AT_COMMIT SyncProvider.GRADE_CHECK_ALL_AT_COMMIT SyncProvider.GRADE_LOCK_WHEN_MODIFIED SyncProvider.GRADE_LOCK_WHEN_LOADED Constants to indicate what locks are set on the data source SyncProvider.DATASOURCE_NO_LOCK SyncProvider.DATASOURCE_ROW_LOCK SyncProvider.DATASOURCE_TABLE_LOCK SyncProvider.DATASOURCE_DB_LOCK Constants to indicate whether a SyncProvider object can perform updates to an SQL VIEW These constants are explained in the preceding section (4.0). SyncProvider.UPDATABLE_VIEW_SYNC SyncProvider.NONUPDATABLE_VIEW_SYNC
Indicates an error with the SyncProvider mechanism. This exception is created by a SyncProvider abstract class extension if it encounters violations in reading from or writing to the originating data source.
If it is implemented to do so, the SyncProvider object may also create a SyncResolver object and either initialize the SyncProviderException object with it at construction time or set it with the SyncProvider object at a later time.
The method acceptChanges will throw this exception after the writer has finished checking for conflicts and has found one or more conflicts. An application may catch a SyncProviderException object and call its getSyncResolver method to get its SyncResolver object. See the code fragment in the interface comment for SyncResolver for an example. This SyncResolver object will mirror the RowSet 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 SyncResolver object will be null.
The SyncResolver 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.
A SyncProviderException object may or may not contain a description of the condition causing the exception. The inherited method getMessage may be called to retrieve the description if there is one.
Indicates an error with the SyncProvider mechanism. This exception is created by a SyncProvider abstract class extension if it encounters violations in reading from or writing to the originating data source. If it is implemented to do so, the SyncProvider object may also create a SyncResolver object and either initialize the SyncProviderException object with it at construction time or set it with the SyncProvider object at a later time. The method acceptChanges will throw this exception after the writer has finished checking for conflicts and has found one or more conflicts. An application may catch a SyncProviderException object and call its getSyncResolver method to get its SyncResolver object. See the code fragment in the interface comment for SyncResolver for an example. This SyncResolver object will mirror the RowSet 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 SyncResolver object will be null. The SyncResolver 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. A SyncProviderException object may or may not contain a description of the condition causing the exception. The inherited method getMessage may be called to retrieve the description if there is one.
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.
Note that a conflict is a situation where the RowSet 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 RowSet object's original values are the values it had just prior to the the last synchronization, which are not necessarily its initial values.
Description of a SyncResolver Object
A SyncResolver object is a specialized RowSet object that implements the SyncResolver interface. It may operate as either a connected RowSet object (an implementation of the JdbcRowSet interface) or a connected RowSet object (an implementation of the CachedRowSet interface or one of its subinterfaces). For information on the subinterfaces, see the javax.sql.rowset package description. The reference implementation for SyncResolver implements the CachedRowSet interface, but other implementations may choose to implement the JdbcRowSet interface to satisfy particular needs.
After an application has attempted to synchronize a RowSet object with the data source (by calling the CachedRowSet method acceptChanges), and one or more conflicts have been found, a rowset's SyncProvider object creates an instance of SyncResolver. This new SyncResolver object has the same number of rows and columns as the RowSet object that was attempting the synchronization. The SyncResolver object contains the values from the data source that caused the conflict(s) and null for all other values. In addition, it contains information about each conflict.
Getting and Using a SyncResolver Object
When the method acceptChanges encounters conflicts, the SyncProvider object creates a SyncProviderException object and sets it with the new SyncResolver object. The method acceptChanges will throw this exception, which the application can then catch and use to retrieve the SyncResolver object it contains. The following code snippet uses the SyncProviderException method getSyncResolver to get the SyncResolver object resolver.
catch (SyncProviderException spe) {
SyncResolver resolver = spe.getSyncResolver();
...
}
}
With resolver in hand, an application can use it to get the information it contains about the conflict or conflicts. A SyncResolver object such as resolver 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.
The following kinds of information can be obtained from a SyncResolver object:
What operation was being attempted when a conflict occurred The SyncProvider interface defines four constants describing states that may occur. Three constants describe the type of operation (update, delete, or insert) that a RowSet 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 SyncResolver object calls the method getStatus.
int operation = resolver.getStatus();
The value in the data source that caused a conflict A conflict exists when a value that a RowSet 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 SyncResolver method getConflictValue to retrieve the value in the data source that is the cause of the conflict because the values in a SyncResolver object are the conflict values from the data source.
java.lang.Object conflictValue = resolver.getConflictValue(2);
Note that the column in resolver can be designated by the column number, as is done in the preceding line of code, or by the column name.
With the information retrieved from the methods getStatus and getConflictValue, the application may make a determination as to which value should be persisted in the data source. The application then calls the SyncResolver method setResolvedValue, which sets the value to be persisted in the RowSet object and also in the data source.
resolver.setResolvedValue(`DEPT`, 8390426);
In the preceding line of code, the column name designates the column in the RowSet object that is to be set with the given value. The column number can also be used to designate the column.
An application calls the method setResolvedValue after it has resolved all of the conflicts in the current conflict row and repeats this process for each conflict row in the SyncResolver object.
Navigating a SyncResolver Object
Because a SyncResolver object is a RowSet object, an application can use all of the RowSet methods for moving the cursor to navigate a SyncResolver object. For example, an application can use the RowSet method next to get to each row and then call the SyncResolver method getStatus 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.
To make it easier to navigate a SyncResolver object, especially when there are large numbers of rows with no conflicts, the SyncResolver interface defines the methods nextConflict and previousConflict, which move only to rows that contain at least one conflict value. Then an application can call the SyncResolver method getConflictValue, supplying it with the column number, to get the conflict value itself. The code fragment in the next section gives an example.
Code Example
The following code fragment demonstrates how a disconnected RowSet object crs might attempt to synchronize itself with the underlying data source and then resolve the conflicts. In the try block, crs calls the method acceptChanges, passing it the Connection object con. If there are no conflicts, the changes in crs are simply written to the data source. However, if there is a conflict, the method acceptChanges throws a SyncProviderException object, and the catch block takes effect. In this example, which illustrates one of the many ways a SyncResolver object can be used, the SyncResolver method nextConflict is used in a while loop. The loop will end when nextConflict returns false, which will occur when there are no more conflict rows in the SyncResolver object resolver. In This particular code fragment, resolver looks for rows that have update conflicts (rows with the status SyncResolver.UPDATE_ROW_CONFLICT), and the rest of this code fragment executes only for rows where conflicts occurred because crs was attempting an update.
After the cursor for resolver has moved to the next conflict row that has an update conflict, the method getRow indicates the number of the current row, and the cursor for the CachedRowSet object crs is moved to the comparable row in crs. By iterating through the columns of that row in both resolver and crs, the conflicting values can be retrieved and compared to decide which one should be persisted. In this code fragment, the value in crs is the one set as the resolved value, which means that it will be used to overwrite the conflict value in the data source.
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);
}
}
}
}
}
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. Note that a conflict is a situation where the RowSet 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 RowSet object's original values are the values it had just prior to the the last synchronization, which are not necessarily its initial values. Description of a SyncResolver Object A SyncResolver object is a specialized RowSet object that implements the SyncResolver interface. It may operate as either a connected RowSet object (an implementation of the JdbcRowSet interface) or a connected RowSet object (an implementation of the CachedRowSet interface or one of its subinterfaces). For information on the subinterfaces, see the javax.sql.rowset package description. The reference implementation for SyncResolver implements the CachedRowSet interface, but other implementations may choose to implement the JdbcRowSet interface to satisfy particular needs. After an application has attempted to synchronize a RowSet object with the data source (by calling the CachedRowSet method acceptChanges), and one or more conflicts have been found, a rowset's SyncProvider object creates an instance of SyncResolver. This new SyncResolver object has the same number of rows and columns as the RowSet object that was attempting the synchronization. The SyncResolver object contains the values from the data source that caused the conflict(s) and null for all other values. In addition, it contains information about each conflict. Getting and Using a SyncResolver Object When the method acceptChanges encounters conflicts, the SyncProvider object creates a SyncProviderException object and sets it with the new SyncResolver object. The method acceptChanges will throw this exception, which the application can then catch and use to retrieve the SyncResolver object it contains. The following code snippet uses the SyncProviderException method getSyncResolver to get the SyncResolver object resolver. catch (SyncProviderException spe) { SyncResolver resolver = spe.getSyncResolver(); ... } } With resolver in hand, an application can use it to get the information it contains about the conflict or conflicts. A SyncResolver object such as resolver 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. The following kinds of information can be obtained from a SyncResolver object: What operation was being attempted when a conflict occurred The SyncProvider interface defines four constants describing states that may occur. Three constants describe the type of operation (update, delete, or insert) that a RowSet 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 SyncResolver object calls the method getStatus. int operation = resolver.getStatus(); The value in the data source that caused a conflict A conflict exists when a value that a RowSet 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 SyncResolver method getConflictValue to retrieve the value in the data source that is the cause of the conflict because the values in a SyncResolver object are the conflict values from the data source. java.lang.Object conflictValue = resolver.getConflictValue(2); Note that the column in resolver can be designated by the column number, as is done in the preceding line of code, or by the column name. With the information retrieved from the methods getStatus and getConflictValue, the application may make a determination as to which value should be persisted in the data source. The application then calls the SyncResolver method setResolvedValue, which sets the value to be persisted in the RowSet object and also in the data source. resolver.setResolvedValue(`DEPT`, 8390426); In the preceding line of code, the column name designates the column in the RowSet object that is to be set with the given value. The column number can also be used to designate the column. An application calls the method setResolvedValue after it has resolved all of the conflicts in the current conflict row and repeats this process for each conflict row in the SyncResolver object. Navigating a SyncResolver Object Because a SyncResolver object is a RowSet object, an application can use all of the RowSet methods for moving the cursor to navigate a SyncResolver object. For example, an application can use the RowSet method next to get to each row and then call the SyncResolver method getStatus 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. To make it easier to navigate a SyncResolver object, especially when there are large numbers of rows with no conflicts, the SyncResolver interface defines the methods nextConflict and previousConflict, which move only to rows that contain at least one conflict value. Then an application can call the SyncResolver method getConflictValue, supplying it with the column number, to get the conflict value itself. The code fragment in the next section gives an example. Code Example The following code fragment demonstrates how a disconnected RowSet object crs might attempt to synchronize itself with the underlying data source and then resolve the conflicts. In the try block, crs calls the method acceptChanges, passing it the Connection object con. If there are no conflicts, the changes in crs are simply written to the data source. However, if there is a conflict, the method acceptChanges throws a SyncProviderException object, and the catch block takes effect. In this example, which illustrates one of the many ways a SyncResolver object can be used, the SyncResolver method nextConflict is used in a while loop. The loop will end when nextConflict returns false, which will occur when there are no more conflict rows in the SyncResolver object resolver. In This particular code fragment, resolver looks for rows that have update conflicts (rows with the status SyncResolver.UPDATE_ROW_CONFLICT), and the rest of this code fragment executes only for rows where conflicts occurred because crs was attempting an update. After the cursor for resolver has moved to the next conflict row that has an update conflict, the method getRow indicates the number of the current row, and the cursor for the CachedRowSet object crs is moved to the comparable row in crs. By iterating through the columns of that row in both resolver and crs, the conflicting values can be retrieved and compared to decide which one should be persisted. In this code fragment, the value in crs is the one set as the resolved value, which means that it will be used to overwrite the conflict value in the data source. 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); } } } } }
A specialized interface that facilitates an extension of the standard SyncProvider abstract class so that it has finer grained transaction control.
If one or more disconnected RowSet 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 CachedRowSet constant COMMIT_ON_ACCEPT_CHANGES to false and use the commit and rollback methods defined in this interface to manage transaction boundaries.
A specialized interface that facilitates an extension of the standard SyncProvider abstract class so that it has finer grained transaction control. If one or more disconnected RowSet 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 CachedRowSet constant COMMIT_ON_ACCEPT_CHANGES to false and use the commit and rollback methods defined in this interface to manage transaction boundaries.
A specialized interface that facilitates an extension of the SyncProvider abstract class for XML orientated synchronization providers.
SyncProvider implementations that supply XML data reader capabilities such as output XML stream capabilities can implement this interface to provide standard XmlReader objects to WebRowSet implementations.
An XmlReader object is registered as the XML reader for a WebRowSet by being assigned to the rowset's xmlReader field. When the WebRowSet object's readXml method is invoked, it in turn invokes its XML reader's readXML method.
A specialized interface that facilitates an extension of the SyncProvider abstract class for XML orientated synchronization providers. SyncProvider implementations that supply XML data reader capabilities such as output XML stream capabilities can implement this interface to provide standard XmlReader objects to WebRowSet implementations. An XmlReader object is registered as the XML reader for a WebRowSet by being assigned to the rowset's xmlReader field. When the WebRowSet object's readXml method is invoked, it in turn invokes its XML reader's readXML method.
A specialized interface that facilitates an extension of the SyncProvider abstract class for XML orientated synchronization providers.
SyncProvider implementations that supply XML data writer capabilities such as output XML stream capabilities can implement this interface to provide standard XmlWriter objects to WebRowSet implementations.
Writing a WebRowSet object includes printing the rowset's data, metadata, and properties, all with the appropriate XML tags.
A specialized interface that facilitates an extension of the SyncProvider abstract class for XML orientated synchronization providers. SyncProvider implementations that supply XML data writer capabilities such as output XML stream capabilities can implement this interface to provide standard XmlWriter objects to WebRowSet implementations. Writing a WebRowSet object includes printing the rowset's data, metadata, and properties, all with the appropriate XML tags.
The standard interface that all implementations of a WebRowSet must implement.
1.0 Overview The WebRowSetImpl provides the standard reference implementation, which may be extended if required.
The standard WebRowSet XML Schema definition is available at the following URI:
http://java.sun.com/xml/ns/jdbc/webrowset.xsd
It describes the standard XML document format required when describing a RowSet object in XML and must be used be all standard implementations of the WebRowSet interface to ensure interoperability. In addition, the 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:
http://standards.iso.org/iso/9075/2002/12/sqlxml
The schema definition describes the internal data of a RowSet object in three distinct areas:
properties - These properties describe the standard synchronization provider properties in addition to the more general RowSet properties.
metadata - This describes the metadata associated with the tabular structure governed by a WebRowSet object. The metadata described is closely aligned with the metadata accessible in the underlying java.sql.ResultSet interface.
data - This describes the original data (the state of data since the last population or last synchronization of the WebRowSet object) and the current data. By keeping track of the delta between the original data and the current data, a WebRowSet maintains the ability to synchronize changes in its data back to the originating data source.
2.0 WebRowSet States The following sections demonstrates how a WebRowSet implementation should use the XML Schema to describe update, insert, and delete operations and to describe the state of a WebRowSet object in XML.
2.1 State 1 - Outputting a WebRowSet Object to XML In this example, a WebRowSet object is created and populated with a simple 2 column, 5 row table from a data source. Having the 5 rows in a 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 CachedRowSet™ interface provide key details that describe WebRowSet properties. Outputting the WebRowSet object to XML using the standard writeXml methods describes the internal properties as follows:
<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> The meta-data describing the make up of the WebRowSet is described in XML as detailed below. Note both columns are described between the column-definition tags.
<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> Having detailed how the properties and metadata are described, the following details how the contents of a WebRowSet object is described in XML. Note, that this describes a WebRowSet object that has not undergone any modifications since its instantiation. A currentRow tag is mapped to each row of the table structure that the WebRowSet object provides. A columnValue tag may contain either the stringData or binaryData tag, according to the SQL type that the XML value is mapping back to. The binaryData tag contains data in the Base64 encoding and is typically used for BLOB and CLOB type data.
<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> 2.2 State 2 - Deleting a Row Deleting a row in a WebRowSet object involves simply moving to the row to be deleted and then calling the method deleteRow, as in any other RowSet object. The following two lines of code, in which wrs is a WebRowSet object, delete the third row.
wrs.absolute(3);
wrs.deleteRow();
The XML description shows the third row is marked as a deleteRow, which eliminates the third row in the WebRowSet object.
<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> 2.3 State 3 - Inserting a Row A 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 insertRow.
wrs.moveToInsertRow();
wrs.updateString(1, fifththrow
);
wrs.updateString(2, 5
);
wrs.insertRow();
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 next moves the cursor to the correct row.
Calling the method acceptChanges writes the change to the data source.
wrs.moveToCurrentRow();
wrs.next();
wrs.updateString(2, V
);
wrs.acceptChanges();
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.
<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> 2.4 State 4 - Modifying a Row 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.
wrs.absolute(5);
wrs.updateString(1, new4thRow
);
wrs.updateString(2, IV
);
wrs.updateRow();
In XML, this is described by the modifyRow tag. Both the original and new
values are contained within the tag for original row tracking purposes.
<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>
The standard interface that all implementations of a WebRowSet must implement. 1.0 Overview The WebRowSetImpl provides the standard reference implementation, which may be extended if required. The standard WebRowSet XML Schema definition is available at the following URI: http://java.sun.com/xml/ns/jdbc/webrowset.xsd It describes the standard XML document format required when describing a RowSet object in XML and must be used be all standard implementations of the WebRowSet interface to ensure interoperability. In addition, the 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: http://standards.iso.org/iso/9075/2002/12/sqlxml The schema definition describes the internal data of a RowSet object in three distinct areas: properties - These properties describe the standard synchronization provider properties in addition to the more general RowSet properties. metadata - This describes the metadata associated with the tabular structure governed by a WebRowSet object. The metadata described is closely aligned with the metadata accessible in the underlying java.sql.ResultSet interface. data - This describes the original data (the state of data since the last population or last synchronization of the WebRowSet object) and the current data. By keeping track of the delta between the original data and the current data, a WebRowSet maintains the ability to synchronize changes in its data back to the originating data source. 2.0 WebRowSet States The following sections demonstrates how a WebRowSet implementation should use the XML Schema to describe update, insert, and delete operations and to describe the state of a WebRowSet object in XML. 2.1 State 1 - Outputting a WebRowSet Object to XML In this example, a WebRowSet object is created and populated with a simple 2 column, 5 row table from a data source. Having the 5 rows in a 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 CachedRowSet™ interface provide key details that describe WebRowSet properties. Outputting the WebRowSet object to XML using the standard writeXml methods describes the internal properties as follows: <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> The meta-data describing the make up of the WebRowSet is described in XML as detailed below. Note both columns are described between the column-definition tags. <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> Having detailed how the properties and metadata are described, the following details how the contents of a WebRowSet object is described in XML. Note, that this describes a WebRowSet object that has not undergone any modifications since its instantiation. A currentRow tag is mapped to each row of the table structure that the WebRowSet object provides. A columnValue tag may contain either the stringData or binaryData tag, according to the SQL type that the XML value is mapping back to. The binaryData tag contains data in the Base64 encoding and is typically used for BLOB and CLOB type data. <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> 2.2 State 2 - Deleting a Row Deleting a row in a WebRowSet object involves simply moving to the row to be deleted and then calling the method deleteRow, as in any other RowSet object. The following two lines of code, in which wrs is a WebRowSet object, delete the third row. wrs.absolute(3); wrs.deleteRow(); The XML description shows the third row is marked as a deleteRow, which eliminates the third row in the WebRowSet object. <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> 2.3 State 3 - Inserting a Row A 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 insertRow. wrs.moveToInsertRow(); wrs.updateString(1, `fifththrow`); wrs.updateString(2, `5`); wrs.insertRow(); 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 next moves the cursor to the correct row. Calling the method acceptChanges writes the change to the data source. wrs.moveToCurrentRow(); wrs.next(); wrs.updateString(2, `V`); wrs.acceptChanges(); 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. <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> 2.4 State 4 - Modifying a Row 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. wrs.absolute(5); wrs.updateString(1, `new4thRow`); wrs.updateString(2, `IV`); wrs.updateRow(); In XML, this is described by the modifyRow tag. Both the original and new values are contained within the tag for original row tracking purposes. <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>
An Event object generated when an event occurs to a RowSet object. A RowSetEvent object is generated when a single row in a rowset is changed, the whole rowset is changed, or the rowset cursor moves.
When an event occurs on a RowSet object, one of the RowSetListener methods will be sent to all registered listeners to notify them of the event. An Event object is supplied to the RowSetListener method so that the listener can use it to find out which RowSet object is the source of the event.
An Event object generated when an event occurs to a RowSet object. A RowSetEvent object is generated when a single row in a rowset is changed, the whole rowset is changed, or the rowset cursor moves. When an event occurs on a RowSet object, one of the RowSetListener methods will be sent to all registered listeners to notify them of the event. An Event object is supplied to the RowSetListener method so that the listener can use it to find out which RowSet object is the source of the event.
The interface that a RowSet object implements in order to present itself to a RowSetReader or RowSetWriter object. The RowSetInternal interface contains methods that let the reader or writer access and modify the internal state of the rowset.
The interface that a RowSet object implements in order to present itself to a RowSetReader or RowSetWriter object. The RowSetInternal interface contains methods that let the reader or writer access and modify the internal state of the rowset.
An interface that must be implemented by a component that wants to be notified when a significant event happens in the life of a RowSet object. A component becomes a listener by being registered with a RowSet object via the method RowSet.addRowSetListener. How a registered component implements this interface determines what it does when it is notified of an event.
An interface that must be implemented by a component that wants to be notified when a significant event happens in the life of a RowSet object. A component becomes a listener by being registered with a RowSet object via the method RowSet.addRowSetListener. How a registered component implements this interface determines what it does when it is notified of an event.
An object that contains information about the columns in a RowSet object. This interface is an extension of the ResultSetMetaData interface with methods for setting the values in a RowSetMetaData object. When a RowSetReader object reads data into a RowSet object, it creates a RowSetMetaData object and initializes it using the methods in the RowSetMetaData interface. Then the reader passes the RowSetMetaData object to the rowset.
The methods in this interface are invoked internally when an application calls the method RowSet.execute; an application programmer would not use them directly.
An object that contains information about the columns in a RowSet object. This interface is an extension of the ResultSetMetaData interface with methods for setting the values in a RowSetMetaData object. When a RowSetReader object reads data into a RowSet object, it creates a RowSetMetaData object and initializes it using the methods in the RowSetMetaData interface. Then the reader passes the RowSetMetaData object to the rowset. The methods in this interface are invoked internally when an application calls the method RowSet.execute; an application programmer would not use them directly.
The facility that a disconnected RowSet object calls on to populate itself with rows of data. A reader (an object implementing the RowSetReader interface) may be registered with a RowSet object that supports the reader/writer paradigm. When the RowSet object's execute method is called, it in turn calls the reader's readData method.
The facility that a disconnected RowSet object calls on to populate itself with rows of data. A reader (an object implementing the RowSetReader interface) may be registered with a RowSet object that supports the reader/writer paradigm. When the RowSet object's execute method is called, it in turn calls the reader's readData method.
An object that implements the RowSetWriter interface, called a writer. A writer may be registered with a RowSet object that supports the reader/writer paradigm.
If a disconnected RowSet object modifies some of its data, and it has a writer associated with it, it may be implemented so that it calls on the writer's writeData method internally to write the updates back to the data source. In order to do this, the writer must first establish a connection with the rowset's data source.
If the data to be updated has already been changed in the data source, there is a conflict, in which case the writer will not write the changes to the data source. The algorithm the writer uses for preventing or limiting conflicts depends entirely on its implementation.
An object that implements the RowSetWriter interface, called a writer. A writer may be registered with a RowSet object that supports the reader/writer paradigm. If a disconnected RowSet object modifies some of its data, and it has a writer associated with it, it may be implemented so that it calls on the writer's writeData method internally to write the updates back to the data source. In order to do this, the writer must first establish a connection with the rowset's data source. If the data to be updated has already been changed in the data source, there is a conflict, in which case the writer will not write the changes to the data source. The algorithm the writer uses for preventing or limiting conflicts depends entirely on its implementation.
A StatementEvent is sent to all StatementEventListeners which were registered with a PooledConnection. This occurs when the driver determines that a PreparedStatement that is associated with the PooledConnection has been closed or the driver determines is invalid.
A StatementEvent is sent to all StatementEventListeners which were registered with a PooledConnection. This occurs when the driver determines that a PreparedStatement that is associated with the PooledConnection has been closed or the driver determines is invalid.
An object that registers to be notified of events that occur on PreparedStatements that are in the Statement pool.
The JDBC 3.0 specification added the maxStatements ConnectionPooledDataSource property to provide a standard mechanism for enabling the pooling of PreparedStatements and to specify the size of the statement pool. However, there was no way for a driver to notify an external statement pool when a PreparedStatement becomes invalid. For some databases, a statement becomes invalid if a DDL operation is performed that affects the table. For example an application may create a temporary table to do some work on the table and then destroy it. It may later recreate the same table when it is needed again. Some databases will invalidate any prepared statements that reference the temporary table when the table is dropped.
Similar to the methods defined in the ConnectionEventListener interface, the driver will call the StatementEventListener.statementErrorOccurred method prior to throwing any exceptions when it detects a statement is invalid. The driver will also call the StatementEventListener.statementClosed method when a PreparedStatement is closed.
Methods which allow a component to register a StatementEventListener with a PooledConnection have been added to the PooledConnection interface.
An object that registers to be notified of events that occur on PreparedStatements that are in the Statement pool. The JDBC 3.0 specification added the maxStatements ConnectionPooledDataSource property to provide a standard mechanism for enabling the pooling of PreparedStatements and to specify the size of the statement pool. However, there was no way for a driver to notify an external statement pool when a PreparedStatement becomes invalid. For some databases, a statement becomes invalid if a DDL operation is performed that affects the table. For example an application may create a temporary table to do some work on the table and then destroy it. It may later recreate the same table when it is needed again. Some databases will invalidate any prepared statements that reference the temporary table when the table is dropped. Similar to the methods defined in the ConnectionEventListener interface, the driver will call the StatementEventListener.statementErrorOccurred method prior to throwing any exceptions when it detects a statement is invalid. The driver will also call the StatementEventListener.statementClosed method when a PreparedStatement is closed. Methods which allow a component to register a StatementEventListener with a PooledConnection have been added to the PooledConnection interface.
An object that provides support for distributed transactions. An XAConnection object may be enlisted in a distributed transaction by means of an XAResource object. A transaction manager, usually part of a middle tier server, manages an XAConnection object through the XAResource object.
An application programmer does not use this interface directly; rather, it is used by a transaction manager working in the middle tier server.
An object that provides support for distributed transactions. An XAConnection object may be enlisted in a distributed transaction by means of an XAResource object. A transaction manager, usually part of a middle tier server, manages an XAConnection object through the XAResource object. An application programmer does not use this interface directly; rather, it is used by a transaction manager working in the middle tier server.
A factory for XAConnection objects that is used internally. An object that implements the XADataSource interface is typically registered with a naming service that uses the Java Naming and Directory Interface™ (JNDI).
An implementation of XADataSource must include a public no-arg constructor.
A factory for XAConnection objects that is used internally. An object that implements the XADataSource interface is typically registered with a naming service that uses the Java Naming and Directory Interface™ (JNDI). An implementation of XADataSource must include a public no-arg constructor.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close