* an application sets the number of rows to be included in a page using the method * <code>setPageSize</code>. 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. * <P> * After properties have been set, * the <code>CachedRowSet</code> object must be populated with data * using either the method <code>populate</code> or the method <code>execute</code>. * The following lines of code demonstrate using the method <code>populate</code>. * Note that this version of the method takes two parameters, a <code>ResultSet</code> * handle and the row in the <code>ResultSet</code> object from which to start * retrieving rows. * <PRE> * CachedRowSet crs = new CachedRowSetImpl(); * crs.setMaxRows(20); * crs.setPageSize(4); * crs.populate(rsHandle, 10); * </PRE> * When this code runs, <i>crs</i> will be populated with four rows from * <i>rsHandle</i> starting with the tenth row. * <P> * The next code fragment shows populating a <code>CachedRowSet</code> object using the * method <code>execute</code>, which may or may not take a <code>Connection</code> * object as a parameter. This code passes <code>execute</code> the <code>Connection</code> * object <i>conHandle</i>. * <P> * Note that there are two differences between the following code * fragment and the previous one. First, the method <code>setMaxRows</code> is not * called, so there is no limit set for the number of rows that <i>crs</i> may contain. * (Remember that <i>crs</i> 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 * <code>execute</code> the number of the row in the <code>ResultSet</code> object * from which to start retrieving rows. This method always starts with the first row. * <PRE> * CachedRowSet crs = new CachedRowSetImpl(); * crs.setPageSize(5); * crs.execute(conHandle); * </PRE> * After this code has run, <i>crs</i> will contain five rows of data from the * <code>ResultSet</code> object produced by the command for <i>crs</i>. The writer * for <i>crs</i> will use <i>conHandle</i> to connect to the data source and * execute the command for <i>crs</i>. An application is then able to operate on the * data in <i>crs</i> in the same way that it would operate on data in any other * <code>CachedRowSet</code> object. * <P> * To access the next page (chunk of data), an application calls the method * <code>nextPage</code>. This method creates a new <code>CachedRowSet</code> object * and fills it with the next page of data. For example, assume that the * <code>CachedRowSet</code> object's command returns a <code>ResultSet</code> object * <i>rs</i> with 1000 rows of data. If the page size has been set to 100, the first * call to the method <code>nextPage</code> will create a <code>CachedRowSet</code> object * containing the first 100 rows of <i>rs</i>. After doing what it needs to do with the * data in these first 100 rows, the application can again call the method * <code>nextPage</code> to create another <code>CachedRowSet</code> object * with the second 100 rows from <i>rs</i>. The data from the first <code>CachedRowSet</code> * object will no longer be in memory because it is replaced with the data from the * second <code>CachedRowSet</code> object. After the tenth call to the method <code>nextPage</code>, * the tenth <code>CachedRowSet</code> object will contain the last 100 rows of data from * <i>rs</i>, which are stored in memory. At any given time, the data from only one * <code>CachedRowSet</code> object is stored in memory. * <P> * The method <code>nextPage</code> returns <code>true</code> as long as the current * page is not the last page of rows and <code>false</code> when there are no more pages. * It can therefore be used in a <code>while</code> loop to retrieve all of the pages, * as is demonstrated in the following lines of code. * <PRE> * 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 * } * } * </PRE> * 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. * <P> * The <code>CachedRowSet</code> interface also defines the method <code>previousPage</code>. * Just as the method <code>nextPage</code> is analogous to the <code>ResultSet</code> * method <code>next</code>, the method <code>previousPage</code> is analogous to * the <code>ResultSet</code> method <code>previous</code>. Similar to the method * <code>nextPage</code>, <code>previousPage</code> creates a <code>CachedRowSet</code> * object containing the number of rows set as the page size. So, for instance, the * method <code>previousPage</code> could be used in a <code>while</code> 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 <code>previousPage</code> is also similar to <code>nextPage</code> * in that it can be used in a <code>while</code> * loop, except that it returns <code>true</code> as long as there is another page * preceding it and <code>false</code> when there are no more pages ahead of it. * <P> * By positioning the cursor after the last row for each page, * as is done in the following code fragment, the method <code>previous</code> * 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 <code>next</code> in a <code>while</code> loop to navigate each page * from the first row to the last row. * <P> * The following code fragment assumes a continuation from the previous code fragment, * meaning that the cursor for the tenth <code>CachedRowSet</code> object is on the * last row. The code moves the cursor to after the last row so that the first * call to the method <code>previous</code> will put the cursor back on the last row. * After going through all of the rows in the last page (the <code>CachedRowSet</code> * object <i>crs</i>), the code then enters * the <code>while</code> 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. * * <PRE> * 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 * } * } * </PRE> * * @author Jonathan Bruce */ public interface CachedRowSet extends RowSet, Joinable { /** * Populates this <code>CachedRowSet</code> object with data from * the given <code>ResultSet</code> object. * <P> * This method can be used as an alternative to the <code>execute</code> method when an * application has a connection to an open <code>ResultSet</code> object. * Using the method <code>populate</code> can be more efficient than using * the version of the <code>execute</code> method that takes no parameters * because it does not open a new connection and re-execute this * <code>CachedRowSet</code> object's command. Using the <code>populate</code> * method is more a matter of convenience when compared to using the version * of <code>execute</code> that takes a <code>ResultSet</code> object. * * @param data the <code>ResultSet</code> object containing the data * to be read into this <code>CachedRowSet</code> object * @throws SQLException if a null <code>ResultSet</code> object is supplied * or this <code>CachedRowSet</code> object cannot * retrieve the associated <code>ResultSetMetaData</code> object * @see #execute * @see java.sql.ResultSet * @see java.sql.ResultSetMetaData */ public void populate(ResultSet data) throws SQLException; /** * Populates this <code>CachedRowSet</code> object with data, using the * given connection to produce the result set from which the data will be read. * This method should close any database connections that it creates to * ensure that this <code>CachedRowSet</code> object is disconnected except when * it is reading data from its data source or writing data to its data source. * <P> * The reader for this <code>CachedRowSet</code> object * will use <i>conn</i> to establish a connection to the data source * so that it can execute the rowset's command and read data from the * the resulting <code>ResultSet</code> object into this * <code>CachedRowSet</code> object. This method also closes <i>conn</i> * after it has populated this <code>CachedRowSet</code> object. * <P> * If this method is called when an implementation has already been * populated, the contents and the metadata are (re)set. Also, if this method is * called before the method <code>acceptChanges</code> has been called * to commit outstanding updates, those updates are lost. * * @param conn a standard JDBC <code>Connection</code> object with valid * properties * @throws SQLException if an invalid <code>Connection</code> object is supplied * or an error occurs in establishing the connection to the * data source * @see #populate * @see java.sql.Connection */ public void execute(Connection conn) throws SQLException; /** * Propagates row update, insert and delete changes made to this * <code>CachedRowSet</code> object to the underlying data source. * <P> * This method calls on this <code>CachedRowSet</code> object's writer * to do the work behind the scenes. * Standard <code>CachedRowSet</code> implementations should use the * <code>SyncFactory</code> singleton * to obtain a <code>SyncProvider</code> instance providing a * <code>RowSetWriter</code> object (writer). The writer will attempt * to propagate changes made in this <code>CachedRowSet</code> object * back to the data source. * <P> * When the method <code>acceptChanges</code> executes successfully, in * addition to writing changes to the data source, it * makes the values in the current row be the values in the original row. * <P> * Depending on the synchronization level of the <code>SyncProvider</code> * implementation being used, the writer will compare the original values * with those in the data source to check for conflicts. When there is a conflict, * the <code>RIOptimisticProvider</code> implementation, for example, throws a * <code>SyncProviderException</code> and does not write anything to the * data source. * <P> * An application may choose to catch the <code>SyncProviderException</code> * object and retrieve the <code>SyncResolver</code> object it contains. * The <code>SyncResolver</code> object lists the conflicts row by row and * sets a lock on the data source to avoid further conflicts while the * current conflicts are being resolved. * Further, for each conflict, it provides methods for examining the conflict * and setting the value that should be persisted in the data source. * After all conflicts have been resolved, an application must call the * <code>acceptChanges</code> method again to write resolved values to the * data source. If all of the values in the data source are already the * values to be persisted, the method <code>acceptChanges</code> does nothing. * <P> * Some provider implementations may use locks to ensure that there are no * conflicts. In such cases, it is guaranteed that the writer will succeed in * writing changes to the data source when the method <code>acceptChanges</code> * is called. This method may be called immediately after the methods * <code>updateRow</code>, <code>insertRow</code>, or <code>deleteRow</code> * have been called, but it is more efficient to call it only once after * all changes have been made so that only one connection needs to be * established. * <P> * Note: The <code>acceptChanges()</code> method will determine if the * <code>COMMIT_ON_ACCEPT_CHANGES</code> is set to true or not. If it is set * to true, all updates in the synchronization are committed to the data * source. Otherwise, the application <b>must</b> explicity call the * <code>commit()</code> or <code>rollback()</code> methods as appropriate. * * @throws SQLException if the cursor is on the insert row * @throws SyncProviderException if the underlying * synchronization provider's writer fails to write the updates * back to the data source * @see #acceptChanges(java.sql.Connection) * @see javax.sql.RowSetWriter * @see javax.sql.rowset.spi.SyncFactory * @see javax.sql.rowset.spi.SyncProvider * @see javax.sql.rowset.spi.SyncProviderException * @see javax.sql.rowset.spi.SyncResolver */ public void acceptChanges() throws SyncProviderException; /** * Propagates all row update, insert and delete changes to the * data source backing this <code>CachedRowSet</code> object * using the specified <code>Connection</code> object to establish a * connection to the data source. * <P> * The other version of the <code>acceptChanges</code> method is not passed * a connection because it uses * the <code>Connection</code> object already defined within the <code>RowSet</code> * object, which is the connection used for populating it initially. * <P> * This form of the method <code>acceptChanges</code> is similar to the * form that takes no arguments; however, unlike the other form, this form * can be used only when the underlying data source is a JDBC data source. * The updated <code>Connection</code> properties must be used by the * <code>SyncProvider</code> to reset the <code>RowSetWriter</code> * configuration to ensure that the contents of the <code>CachedRowSet</code> * object are synchronized correctly. * <P> * When the method <code>acceptChanges</code> executes successfully, in * addition to writing changes to the data source, it * makes the values in the current row be the values in the original row. * <P> * Depending on the synchronization level of the <code>SyncProvider</code> * implementation being used, the writer will compare the original values * with those in the data source to check for conflicts. When there is a conflict, * the <code>RIOptimisticProvider</code> implementation, for example, throws a * <code>SyncProviderException</code> and does not write anything to the * data source. * <P> * An application may choose to catch the <code>SyncProviderException</code> * object and retrieve the <code>SyncResolver</code> object it contains. * The <code>SyncResolver</code> object lists the conflicts row by row and * sets a lock on the data source to avoid further conflicts while the * current conflicts are being resolved. * Further, for each conflict, it provides methods for examining the conflict * and setting the value that should be persisted in the data source. * After all conflicts have been resolved, an application must call the * <code>acceptChanges</code> method again to write resolved values to the * data source. If all of the values in the data source are already the * values to be persisted, the method <code>acceptChanges</code> does nothing. * <P> * Some provider implementations may use locks to ensure that there are no * conflicts. In such cases, it is guaranteed that the writer will succeed in * writing changes to the data source when the method <code>acceptChanges</code> * is called. This method may be called immediately after the methods * <code>updateRow</code>, <code>insertRow</code>, or <code>deleteRow</code> * have been called, but it is more efficient to call it only once after * all changes have been made so that only one connection needs to be * established. * <P> * Note: The <code>acceptChanges()</code> method will determine if the * <code>COMMIT_ON_ACCEPT_CHANGES</code> is set to true or not. If it is set * to true, all updates in the synchronization are committed to the data * source. Otherwise, the application <b>must</b> explicity call the * <code>commit</code> or <code>rollback</code> methods as appropriate. * * @param con a standard JDBC <code>Connection</code> object * @throws SQLException if the cursor is on the insert row * @throws SyncProviderException if the underlying * synchronization provider's writer fails to write the updates * back to the data source * @see #acceptChanges() * @see javax.sql.RowSetWriter * @see javax.sql.rowset.spi.SyncFactory * @see javax.sql.rowset.spi.SyncProvider * @see javax.sql.rowset.spi.SyncProviderException * @see javax.sql.rowset.spi.SyncResolver */ public void acceptChanges(Connection con) throws SyncProviderException; /** * Restores this <code>CachedRowSet</code> object to its original * value, that is, its value before the last set of changes. If there * have been no changes to the rowset or only one set of changes, * the original value is the value with which this <code>CachedRowSet</code> object * was populated; otherwise, the original value is * the value it had immediately before its current value. * <P> * When this method is called, a <code>CachedRowSet</code> implementation * must ensure that all updates, inserts, and deletes to the current * rowset instance are replaced by the previous values. In addition, * the cursor should be * reset to the first row and a <code>rowSetChanged</code> event * should be fired to notify all registered listeners. * * @throws SQLException if an error occurs rolling back the current value of * this <code>CachedRowSet</code> object to its previous value * @see javax.sql.RowSetListener#rowSetChanged */ public void restoreOriginal() throws SQLException; /** * Releases the current contents of this <code>CachedRowSet</code> * object and sends a <code>rowSetChanged</code> event to all * registered listeners. Any outstanding updates are discarded and * the rowset contains no rows after this method is called. There * are no interactions with the underlying data source, and any rowset * content, metadata, and content updates should be non-recoverable. * <P> * This <code>CachedRowSet</code> object should lock until its contents and * associated updates are fully cleared, thus preventing 'dirty' reads by * other components that hold a reference to this <code>RowSet</code> object. * In addition, the contents cannot be released * until all all components reading this <code>CachedRowSet</code> object * have completed their reads. This <code>CachedRowSet</code> object * should be returned to normal behavior after firing the * <code>rowSetChanged</code> event. * <P> * The metadata, including JDBC properties and Synchronization SPI * properties, are maintained for future use. It is important that * properties such as the <code>command</code> property be * relevant to the originating data source from which this <code>CachedRowSet</code> * object was originally established. * <P> * This method empties a rowset, as opposed to the <code>close</code> method, * which marks the entire rowset as recoverable to allow the garbage collector * the rowset's Java VM resources. * * @throws SQLException if an error occurs flushing the contents of this * <code>CachedRowSet</code> object * @see javax.sql.RowSetListener#rowSetChanged * @see java.sql.ResultSet#close */ public void release() throws SQLException; /** * Cancels the deletion of the current row and notifies listeners that * a row has changed. After this method is called, the current row is * no longer marked for deletion. This method can be called at any * time during the lifetime of the rowset. * <P> * In addition, multiple cancellations of row deletions can be made * by adjusting the position of the cursor using any of the cursor * position control methods such as: * <ul> * <li><code>CachedRowSet.absolute</code> * <li><code>CachedRowSet.first</code> * <li><code>CachedRowSet.last</code> * </ul> * * @throws SQLException if (1) the current row has not been deleted or * (2) the cursor is on the insert row, before the first row, or * after the last row * @see javax.sql.rowset.CachedRowSet#undoInsert * @see java.sql.ResultSet#cancelRowUpdates */ public void undoDelete() throws SQLException; /** * Immediately removes the current row from this <code>CachedRowSet</code> * object if the row has been inserted, and also notifies listeners that a * row has changed. This method can be called at any time during the * lifetime of a rowset and assuming the current row is within * the exception limitations (see below), it cancels the row insertion * of the current row. * <P> * In addition, multiple cancellations of row insertions can be made * by adjusting the position of the cursor using any of the cursor * position control methods such as: * <ul> * <li><code>CachedRowSet.absolute</code> * <li><code>CachedRowSet.first</code> * <li><code>CachedRowSet.last</code> * </ul> * * @throws SQLException if (1) the current row has not been inserted or (2) * the cursor is before the first row, after the last row, or on the * insert row * @see javax.sql.rowset.CachedRowSet#undoDelete * @see java.sql.ResultSet#cancelRowUpdates */ public void undoInsert() throws SQLException; /** * Immediately reverses the last update operation if the * row has been modified. This method can be * called to reverse updates on all columns until all updates in a row have * been rolled back to their state just prior to the last synchronization * (<code>acceptChanges</code>) or population. This method may also be called * while performing updates to the insert row. * <P> * <code>undoUpdate</code> may be called at any time during the lifetime of a * rowset; however, after a synchronization has occurred, this method has no * effect until further modification to the rowset data has occurred. * * @throws SQLException if the cursor is before the first row or after the last * row in in this <code>CachedRowSet</code> object * @see #undoDelete * @see #undoInsert * @see java.sql.ResultSet#cancelRowUpdates */ public void undoUpdate() throws SQLException; /** * Indicates whether the designated column in the current row of this * <code>CachedRowSet</code> object has been updated. * * @param idx an <code>int</code> identifying the column to be checked for updates * @return <code>true</code> if the designated column has been visibly updated; * <code>false</code> otherwise * @throws SQLException if the cursor is on the insert row, before the first row, * or after the last row * @see java.sql.DatabaseMetaData#updatesAreDetected */ public boolean columnUpdated(int idx) throws SQLException; /** * Indicates whether the designated column in the current row of this * <code>CachedRowSet</code> object has been updated. * * @param columnName a <code>String</code> object giving the name of the * column to be checked for updates * @return <code>true</code> if the column has been visibly updated; * <code>false</code> otherwise * @throws SQLException if the cursor is on the insert row, before the first row, * or after the last row * @see java.sql.DatabaseMetaData#updatesAreDetected */ public boolean columnUpdated(String columnName) throws SQLException; /** * Converts this <code>CachedRowSet</code> object to a <code>Collection</code> * object that contains all of this <code>CachedRowSet</code> object's data. * Implementations have some latitude in * how they can represent this <code>Collection</code> object because of the * abstract nature of the <code>Collection</code> framework. * Each row must be fully represented in either a * general purpose <code>Collection</code> implementation or a specialized * <code>Collection</code> implementation, such as a <code>TreeMap</code> * object or a <code>Vector</code> object. * An SQL <code>NULL</code> column value must be represented as a <code>null</code> * in the Java programming language. * <P> * The standard reference implementation for the <code>CachedRowSet</code> * interface uses a <code>TreeMap</code> object for the rowset, with the * values in each row being contained in <code>Vector</code> objects. It is * expected that most implementations will do the same. * <P> * The <code>TreeMap</code> type of collection guarantees that the map will be in * ascending key order, sorted according to the natural order for the * key's class. * Each key references a <code>Vector</code> object that corresponds to one * row of a <code>RowSet</code> object. Therefore, the size of each * <code>Vector</code> object must be exactly equal to the number of * columns in the <code>RowSet</code> object. * The key used by the <code>TreeMap</code> collection is determined by the * implementation, which may choose to leverage a set key that is * available within the internal <code>RowSet</code> tabular structure byLines 501–1000 of 1625. Previous lines Load more
* an application sets the number of rows to be included in a page using the method * <code>setPageSize</code>. 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. * <P> * After properties have been set, * the <code>CachedRowSet</code> object must be populated with data * using either the method <code>populate</code> or the method <code>execute</code>. * The following lines of code demonstrate using the method <code>populate</code>. * Note that this version of the method takes two parameters, a <code>ResultSet</code> * handle and the row in the <code>ResultSet</code> object from which to start * retrieving rows. * <PRE> * CachedRowSet crs = new CachedRowSetImpl(); * crs.setMaxRows(20); * crs.setPageSize(4); * crs.populate(rsHandle, 10); * </PRE> * When this code runs, <i>crs</i> will be populated with four rows from * <i>rsHandle</i> starting with the tenth row. * <P> * The next code fragment shows populating a <code>CachedRowSet</code> object using the * method <code>execute</code>, which may or may not take a <code>Connection</code> * object as a parameter. This code passes <code>execute</code> the <code>Connection</code> * object <i>conHandle</i>. * <P> * Note that there are two differences between the following code * fragment and the previous one. First, the method <code>setMaxRows</code> is not * called, so there is no limit set for the number of rows that <i>crs</i> may contain. * (Remember that <i>crs</i> 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 * <code>execute</code> the number of the row in the <code>ResultSet</code> object * from which to start retrieving rows. This method always starts with the first row. * <PRE> * CachedRowSet crs = new CachedRowSetImpl(); * crs.setPageSize(5); * crs.execute(conHandle); * </PRE> * After this code has run, <i>crs</i> will contain five rows of data from the * <code>ResultSet</code> object produced by the command for <i>crs</i>. The writer * for <i>crs</i> will use <i>conHandle</i> to connect to the data source and * execute the command for <i>crs</i>. An application is then able to operate on the * data in <i>crs</i> in the same way that it would operate on data in any other * <code>CachedRowSet</code> object. * <P> * To access the next page (chunk of data), an application calls the method * <code>nextPage</code>. This method creates a new <code>CachedRowSet</code> object * and fills it with the next page of data. For example, assume that the * <code>CachedRowSet</code> object's command returns a <code>ResultSet</code> object * <i>rs</i> with 1000 rows of data. If the page size has been set to 100, the first * call to the method <code>nextPage</code> will create a <code>CachedRowSet</code> object * containing the first 100 rows of <i>rs</i>. After doing what it needs to do with the * data in these first 100 rows, the application can again call the method * <code>nextPage</code> to create another <code>CachedRowSet</code> object * with the second 100 rows from <i>rs</i>. The data from the first <code>CachedRowSet</code> * object will no longer be in memory because it is replaced with the data from the * second <code>CachedRowSet</code> object. After the tenth call to the method <code>nextPage</code>, * the tenth <code>CachedRowSet</code> object will contain the last 100 rows of data from * <i>rs</i>, which are stored in memory. At any given time, the data from only one * <code>CachedRowSet</code> object is stored in memory. * <P> * The method <code>nextPage</code> returns <code>true</code> as long as the current * page is not the last page of rows and <code>false</code> when there are no more pages. * It can therefore be used in a <code>while</code> loop to retrieve all of the pages, * as is demonstrated in the following lines of code. * <PRE> * 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 * } * } * </PRE> * 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. * <P> * The <code>CachedRowSet</code> interface also defines the method <code>previousPage</code>. * Just as the method <code>nextPage</code> is analogous to the <code>ResultSet</code> * method <code>next</code>, the method <code>previousPage</code> is analogous to * the <code>ResultSet</code> method <code>previous</code>. Similar to the method * <code>nextPage</code>, <code>previousPage</code> creates a <code>CachedRowSet</code> * object containing the number of rows set as the page size. So, for instance, the * method <code>previousPage</code> could be used in a <code>while</code> 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 <code>previousPage</code> is also similar to <code>nextPage</code> * in that it can be used in a <code>while</code> * loop, except that it returns <code>true</code> as long as there is another page * preceding it and <code>false</code> when there are no more pages ahead of it. * <P> * By positioning the cursor after the last row for each page, * as is done in the following code fragment, the method <code>previous</code> * 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 <code>next</code> in a <code>while</code> loop to navigate each page * from the first row to the last row. * <P> * The following code fragment assumes a continuation from the previous code fragment, * meaning that the cursor for the tenth <code>CachedRowSet</code> object is on the * last row. The code moves the cursor to after the last row so that the first * call to the method <code>previous</code> will put the cursor back on the last row. * After going through all of the rows in the last page (the <code>CachedRowSet</code> * object <i>crs</i>), the code then enters * the <code>while</code> 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. * * <PRE> * 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 * } * } * </PRE> * * @author Jonathan Bruce */ public interface CachedRowSet extends RowSet, Joinable { /** * Populates this <code>CachedRowSet</code> object with data from * the given <code>ResultSet</code> object. * <P> * This method can be used as an alternative to the <code>execute</code> method when an * application has a connection to an open <code>ResultSet</code> object. * Using the method <code>populate</code> can be more efficient than using * the version of the <code>execute</code> method that takes no parameters * because it does not open a new connection and re-execute this * <code>CachedRowSet</code> object's command. Using the <code>populate</code> * method is more a matter of convenience when compared to using the version * of <code>execute</code> that takes a <code>ResultSet</code> object. * * @param data the <code>ResultSet</code> object containing the data * to be read into this <code>CachedRowSet</code> object * @throws SQLException if a null <code>ResultSet</code> object is supplied * or this <code>CachedRowSet</code> object cannot * retrieve the associated <code>ResultSetMetaData</code> object * @see #execute * @see java.sql.ResultSet * @see java.sql.ResultSetMetaData */ public void populate(ResultSet data) throws SQLException; /** * Populates this <code>CachedRowSet</code> object with data, using the * given connection to produce the result set from which the data will be read. * This method should close any database connections that it creates to * ensure that this <code>CachedRowSet</code> object is disconnected except when * it is reading data from its data source or writing data to its data source. * <P> * The reader for this <code>CachedRowSet</code> object * will use <i>conn</i> to establish a connection to the data source * so that it can execute the rowset's command and read data from the * the resulting <code>ResultSet</code> object into this * <code>CachedRowSet</code> object. This method also closes <i>conn</i> * after it has populated this <code>CachedRowSet</code> object. * <P> * If this method is called when an implementation has already been * populated, the contents and the metadata are (re)set. Also, if this method is * called before the method <code>acceptChanges</code> has been called * to commit outstanding updates, those updates are lost. * * @param conn a standard JDBC <code>Connection</code> object with valid * properties * @throws SQLException if an invalid <code>Connection</code> object is supplied * or an error occurs in establishing the connection to the * data source * @see #populate * @see java.sql.Connection */ public void execute(Connection conn) throws SQLException; /** * Propagates row update, insert and delete changes made to this * <code>CachedRowSet</code> object to the underlying data source. * <P> * This method calls on this <code>CachedRowSet</code> object's writer * to do the work behind the scenes. * Standard <code>CachedRowSet</code> implementations should use the * <code>SyncFactory</code> singleton * to obtain a <code>SyncProvider</code> instance providing a * <code>RowSetWriter</code> object (writer). The writer will attempt * to propagate changes made in this <code>CachedRowSet</code> object * back to the data source. * <P> * When the method <code>acceptChanges</code> executes successfully, in * addition to writing changes to the data source, it * makes the values in the current row be the values in the original row. * <P> * Depending on the synchronization level of the <code>SyncProvider</code> * implementation being used, the writer will compare the original values * with those in the data source to check for conflicts. When there is a conflict, * the <code>RIOptimisticProvider</code> implementation, for example, throws a * <code>SyncProviderException</code> and does not write anything to the * data source. * <P> * An application may choose to catch the <code>SyncProviderException</code> * object and retrieve the <code>SyncResolver</code> object it contains. * The <code>SyncResolver</code> object lists the conflicts row by row and * sets a lock on the data source to avoid further conflicts while the * current conflicts are being resolved. * Further, for each conflict, it provides methods for examining the conflict * and setting the value that should be persisted in the data source. * After all conflicts have been resolved, an application must call the * <code>acceptChanges</code> method again to write resolved values to the * data source. If all of the values in the data source are already the * values to be persisted, the method <code>acceptChanges</code> does nothing. * <P> * Some provider implementations may use locks to ensure that there are no * conflicts. In such cases, it is guaranteed that the writer will succeed in * writing changes to the data source when the method <code>acceptChanges</code> * is called. This method may be called immediately after the methods * <code>updateRow</code>, <code>insertRow</code>, or <code>deleteRow</code> * have been called, but it is more efficient to call it only once after * all changes have been made so that only one connection needs to be * established. * <P> * Note: The <code>acceptChanges()</code> method will determine if the * <code>COMMIT_ON_ACCEPT_CHANGES</code> is set to true or not. If it is set * to true, all updates in the synchronization are committed to the data * source. Otherwise, the application <b>must</b> explicity call the * <code>commit()</code> or <code>rollback()</code> methods as appropriate. * * @throws SQLException if the cursor is on the insert row * @throws SyncProviderException if the underlying * synchronization provider's writer fails to write the updates * back to the data source * @see #acceptChanges(java.sql.Connection) * @see javax.sql.RowSetWriter * @see javax.sql.rowset.spi.SyncFactory * @see javax.sql.rowset.spi.SyncProvider * @see javax.sql.rowset.spi.SyncProviderException * @see javax.sql.rowset.spi.SyncResolver */ public void acceptChanges() throws SyncProviderException; /** * Propagates all row update, insert and delete changes to the * data source backing this <code>CachedRowSet</code> object * using the specified <code>Connection</code> object to establish a * connection to the data source. * <P> * The other version of the <code>acceptChanges</code> method is not passed * a connection because it uses * the <code>Connection</code> object already defined within the <code>RowSet</code> * object, which is the connection used for populating it initially. * <P> * This form of the method <code>acceptChanges</code> is similar to the * form that takes no arguments; however, unlike the other form, this form * can be used only when the underlying data source is a JDBC data source. * The updated <code>Connection</code> properties must be used by the * <code>SyncProvider</code> to reset the <code>RowSetWriter</code> * configuration to ensure that the contents of the <code>CachedRowSet</code> * object are synchronized correctly. * <P> * When the method <code>acceptChanges</code> executes successfully, in * addition to writing changes to the data source, it * makes the values in the current row be the values in the original row. * <P> * Depending on the synchronization level of the <code>SyncProvider</code> * implementation being used, the writer will compare the original values * with those in the data source to check for conflicts. When there is a conflict, * the <code>RIOptimisticProvider</code> implementation, for example, throws a * <code>SyncProviderException</code> and does not write anything to the * data source. * <P> * An application may choose to catch the <code>SyncProviderException</code> * object and retrieve the <code>SyncResolver</code> object it contains. * The <code>SyncResolver</code> object lists the conflicts row by row and * sets a lock on the data source to avoid further conflicts while the * current conflicts are being resolved. * Further, for each conflict, it provides methods for examining the conflict * and setting the value that should be persisted in the data source. * After all conflicts have been resolved, an application must call the * <code>acceptChanges</code> method again to write resolved values to the * data source. If all of the values in the data source are already the * values to be persisted, the method <code>acceptChanges</code> does nothing. * <P> * Some provider implementations may use locks to ensure that there are no * conflicts. In such cases, it is guaranteed that the writer will succeed in * writing changes to the data source when the method <code>acceptChanges</code> * is called. This method may be called immediately after the methods * <code>updateRow</code>, <code>insertRow</code>, or <code>deleteRow</code> * have been called, but it is more efficient to call it only once after * all changes have been made so that only one connection needs to be * established. * <P> * Note: The <code>acceptChanges()</code> method will determine if the * <code>COMMIT_ON_ACCEPT_CHANGES</code> is set to true or not. If it is set * to true, all updates in the synchronization are committed to the data * source. Otherwise, the application <b>must</b> explicity call the * <code>commit</code> or <code>rollback</code> methods as appropriate. * * @param con a standard JDBC <code>Connection</code> object * @throws SQLException if the cursor is on the insert row * @throws SyncProviderException if the underlying * synchronization provider's writer fails to write the updates * back to the data source * @see #acceptChanges() * @see javax.sql.RowSetWriter * @see javax.sql.rowset.spi.SyncFactory * @see javax.sql.rowset.spi.SyncProvider * @see javax.sql.rowset.spi.SyncProviderException * @see javax.sql.rowset.spi.SyncResolver */ public void acceptChanges(Connection con) throws SyncProviderException; /** * Restores this <code>CachedRowSet</code> object to its original * value, that is, its value before the last set of changes. If there * have been no changes to the rowset or only one set of changes, * the original value is the value with which this <code>CachedRowSet</code> object * was populated; otherwise, the original value is * the value it had immediately before its current value. * <P> * When this method is called, a <code>CachedRowSet</code> implementation * must ensure that all updates, inserts, and deletes to the current * rowset instance are replaced by the previous values. In addition, * the cursor should be * reset to the first row and a <code>rowSetChanged</code> event * should be fired to notify all registered listeners. * * @throws SQLException if an error occurs rolling back the current value of * this <code>CachedRowSet</code> object to its previous value * @see javax.sql.RowSetListener#rowSetChanged */ public void restoreOriginal() throws SQLException; /** * Releases the current contents of this <code>CachedRowSet</code> * object and sends a <code>rowSetChanged</code> event to all * registered listeners. Any outstanding updates are discarded and * the rowset contains no rows after this method is called. There * are no interactions with the underlying data source, and any rowset * content, metadata, and content updates should be non-recoverable. * <P> * This <code>CachedRowSet</code> object should lock until its contents and * associated updates are fully cleared, thus preventing 'dirty' reads by * other components that hold a reference to this <code>RowSet</code> object. * In addition, the contents cannot be released * until all all components reading this <code>CachedRowSet</code> object * have completed their reads. This <code>CachedRowSet</code> object * should be returned to normal behavior after firing the * <code>rowSetChanged</code> event. * <P> * The metadata, including JDBC properties and Synchronization SPI * properties, are maintained for future use. It is important that * properties such as the <code>command</code> property be * relevant to the originating data source from which this <code>CachedRowSet</code> * object was originally established. * <P> * This method empties a rowset, as opposed to the <code>close</code> method, * which marks the entire rowset as recoverable to allow the garbage collector * the rowset's Java VM resources. * * @throws SQLException if an error occurs flushing the contents of this * <code>CachedRowSet</code> object * @see javax.sql.RowSetListener#rowSetChanged * @see java.sql.ResultSet#close */ public void release() throws SQLException; /** * Cancels the deletion of the current row and notifies listeners that * a row has changed. After this method is called, the current row is * no longer marked for deletion. This method can be called at any * time during the lifetime of the rowset. * <P> * In addition, multiple cancellations of row deletions can be made * by adjusting the position of the cursor using any of the cursor * position control methods such as: * <ul> * <li><code>CachedRowSet.absolute</code> * <li><code>CachedRowSet.first</code> * <li><code>CachedRowSet.last</code> * </ul> * * @throws SQLException if (1) the current row has not been deleted or * (2) the cursor is on the insert row, before the first row, or * after the last row * @see javax.sql.rowset.CachedRowSet#undoInsert * @see java.sql.ResultSet#cancelRowUpdates */ public void undoDelete() throws SQLException; /** * Immediately removes the current row from this <code>CachedRowSet</code> * object if the row has been inserted, and also notifies listeners that a * row has changed. This method can be called at any time during the * lifetime of a rowset and assuming the current row is within * the exception limitations (see below), it cancels the row insertion * of the current row. * <P> * In addition, multiple cancellations of row insertions can be made * by adjusting the position of the cursor using any of the cursor * position control methods such as: * <ul> * <li><code>CachedRowSet.absolute</code> * <li><code>CachedRowSet.first</code> * <li><code>CachedRowSet.last</code> * </ul> * * @throws SQLException if (1) the current row has not been inserted or (2) * the cursor is before the first row, after the last row, or on the * insert row * @see javax.sql.rowset.CachedRowSet#undoDelete * @see java.sql.ResultSet#cancelRowUpdates */ public void undoInsert() throws SQLException; /** * Immediately reverses the last update operation if the * row has been modified. This method can be * called to reverse updates on all columns until all updates in a row have * been rolled back to their state just prior to the last synchronization * (<code>acceptChanges</code>) or population. This method may also be called * while performing updates to the insert row. * <P> * <code>undoUpdate</code> may be called at any time during the lifetime of a * rowset; however, after a synchronization has occurred, this method has no * effect until further modification to the rowset data has occurred. * * @throws SQLException if the cursor is before the first row or after the last * row in in this <code>CachedRowSet</code> object * @see #undoDelete * @see #undoInsert * @see java.sql.ResultSet#cancelRowUpdates */ public void undoUpdate() throws SQLException; /** * Indicates whether the designated column in the current row of this * <code>CachedRowSet</code> object has been updated. * * @param idx an <code>int</code> identifying the column to be checked for updates * @return <code>true</code> if the designated column has been visibly updated; * <code>false</code> otherwise * @throws SQLException if the cursor is on the insert row, before the first row, * or after the last row * @see java.sql.DatabaseMetaData#updatesAreDetected */ public boolean columnUpdated(int idx) throws SQLException; /** * Indicates whether the designated column in the current row of this * <code>CachedRowSet</code> object has been updated. * * @param columnName a <code>String</code> object giving the name of the * column to be checked for updates * @return <code>true</code> if the column has been visibly updated; * <code>false</code> otherwise * @throws SQLException if the cursor is on the insert row, before the first row, * or after the last row * @see java.sql.DatabaseMetaData#updatesAreDetected */ public boolean columnUpdated(String columnName) throws SQLException; /** * Converts this <code>CachedRowSet</code> object to a <code>Collection</code> * object that contains all of this <code>CachedRowSet</code> object's data. * Implementations have some latitude in * how they can represent this <code>Collection</code> object because of the * abstract nature of the <code>Collection</code> framework. * Each row must be fully represented in either a * general purpose <code>Collection</code> implementation or a specialized * <code>Collection</code> implementation, such as a <code>TreeMap</code> * object or a <code>Vector</code> object. * An SQL <code>NULL</code> column value must be represented as a <code>null</code> * in the Java programming language. * <P> * The standard reference implementation for the <code>CachedRowSet</code> * interface uses a <code>TreeMap</code> object for the rowset, with the * values in each row being contained in <code>Vector</code> objects. It is * expected that most implementations will do the same. * <P> * The <code>TreeMap</code> type of collection guarantees that the map will be in * ascending key order, sorted according to the natural order for the * key's class. * Each key references a <code>Vector</code> object that corresponds to one * row of a <code>RowSet</code> object. Therefore, the size of each * <code>Vector</code> object must be exactly equal to the number of * columns in the <code>RowSet</code> object. * The key used by the <code>TreeMap</code> collection is determined by the * implementation, which may choose to leverage a set key that is * available within the internal <code>RowSet</code> tabular structure by