How Can You Instantiate and Load a New CachedRowSet Object from a Non-JDBC Source? JDBC

You want to create a new CachedRowSet object from a non-JDBC source (such as a file or a spreadsheet). To do so, follow these steps:

  1. Create an object that implements javax.sql.RowSetReader, which loads the data from a non-JDBC source.
  2. Create an object that implements javax.sql.RowSetWriter, which writes the data to a data source (this can be a JDBC data source or a non-JDBC data source).
  3. Register classes created in steps 1 and 2.
  4. Instantiate a CachedRowset object with registered classes.
  5. Invoke CachedRowset.execute() to load the data.
  6. Invoke CachedRowset.acceptChanges() to write the data.

Before creating a CachedRowSet object, a RowSetMetaData object must be created, set up with a description of the data, and attached to the CachedRowset object before loading the actual data from a non-JDBC source. Next, I discuss these steps in detail.

Creating an Object That Implements javax.sql.RowSetReader

This step involves creating a class that implements the javax.sql.RowSetReader interface, which loads the data from a non-JDBC source. According to the J2SE documentation, RowSetReader is 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 RowSetReader interface has only one method:

void readData(RowSetInternal caller)
// Reads the new contents of the calling RowSet object.

The following class (CustomRowSetReader) implements the RowSetReader interface, which loads the data into a CachedRowSet object from a non-JDBC source. According to JDK 1.5, RowSetInternal is an 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.

import java.sql.*;
import javax.sql.*;
import javax.sql.rowset.*;
import com.sun.rowset.*;
public class CustomRowSetReader implements RowSetReader {
public CustomRowSetReader() {
System.out.println("CustomRowSetReader: constructor.");
}
public void readData(RowSetInternal caller) throws SQLException {
System.out.println("--- CustomRowSetReader: begin. ---");
if (caller == null) {
System.out.println("CustomRowSetReader: caller is null.");
return;
}
CachedRowSet crs = (CachedRowSet) caller;
RowSetMetaData rsmd = new RowSetMetaDataImpl();
rsmd.setColumnCount(3);
rsmd.setColumnType(1, Types.VARCHAR);
rsmd.setColumnType(2, Types.INTEGER);
rsmd.setColumnType(3, Types.VARCHAR);
rsmd.setColumnName(1, "col1");
rsmd.setColumnName(2, "col2");
rsmd.setColumnName(3, "col3");
crs.setMetaData( rsmd );
System.out.println("CustomRowSetReader: crs.setMetaData( rsmd );");
crs.moveToInsertRow();
crs.updateString( 1, "StringCol11" ); // value for row 1 column 1
crs.updateInt( 2, 1 ); // value for row 1 column 2
crs.updateString( 3, "StringCol31" ); // value for row 1 column 3
crs.insertRow();
System.out.println("CustomRowSetReader: crs.insertRow() 1");
crs.updateString( 1, "StringCol12" ); // value for row 2 column 1
crs.updateInt( 2, 2 ); // value for row 2 column 2
crs.updateString( 3, "StringCol32" ); // value for row 2 column 3
crs.insertRow();
System.out.println("CustomRowSetReader: crs.insertRow() 2");
crs.moveToCurrentRow();
crs.beforeFirst();
displayRowSet(crs);
crs.beforeFirst();
System.out.println("CustomRowSetReader: end.");
} // end readData
static void displayRowSet(RowSet rs) throws SQLException {
while (rs.next()) {
System.out.println(rs.getRow() + " - " +
rs.getString("col1") + ":" +
rs.getInt("col2") + ":" + rs.getString("col3"));
}
}
}

Creating an Object That Implements javax.sql.RowSetWriter This step involves creating a class that implements the javax.sql.RowSetWriter interface, which writes the data from a CachedRowSet object to a data source. According to the J2SE documentation, an object that implements the RowSetWriter interface, called 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 that the writer uses for preventing or limiting conflicts depends entirely on its implementation.

The RowSetWriter interface has only one method:

boolean writeData(RowSetInternal caller)
// Writes the changes in this RowSetWriter object's rowset
// back to the data source from which it got its data.

The following class (CustomRowSetWriter) implements the RowSetWriter interface, which reads the data from a CachedRowSet object and writes it to a data source:

import java.sql.*;
import javax.sql.*;
import javax.sql.rowset.*;
import com.sun.rowset.*;
public class CustomRowSetWriter implements RowSetWriter {
public CustomRowSetWriter() {
System.out.println("CustomRowSetWriter: constructor.");
}
public boolean writeData(RowSetInternal caller) throws SQLException {
System.out.println("--- CustomRowSetWriter: begin. ---");
if (caller == null) {
System.out.println("CustomRowSetWriter: caller is null.");
return false;
}
CachedRowSet crs = (CachedRowSet) caller;
// for now do not write any data
return true;
}
}

Registering Classes Created in Steps 1 and 2

To register your custom RowSetReader and RowSetWriter, you have to implement the javax.sql.rowset.spi.SyncProvider. SyncProvider is the synchronization mechanism that provides reader and writer capabilities for disconnected RowSet objects. A SyncProvider
implementation is a class that extends the SyncProvider abstract class. The MySyncProvider class registers our custom RowSetReader and RowSetWriter:

import javax.sql.RowSetReader;
import javax.sql.RowSetWriter;
import javax.sql.rowset.spi.SyncProvider;
public class MySyncProvider extends SyncProvider {
private int dataSourceLock;
/**
* creates a default SyncProvider object.
*/
public MySyncProvider() {
System.out.println("MySyncProvider: constructor.");
this.dataSourceLock = SyncProvider.DATASOURCE_NO_LOCK;
}
/**
* Returns the current data source lock severity level active
* in this SyncProvider implementation.
*/
public int getDataSourceLock() {
return this.dataSourceLock;
}
/**
* Returns a constant indicating the grade of synchronization a
* RowSet object can expect from this SyncProvider object.
*/
public int getProviderGrade() {
return SyncProvider.GRADE_NONE;
}
/**
* Returns the unique identifier for this SyncProvider object.
*/
public String getProviderID() {
String id = getClass().getName();
System.out.println("--- MySyncProvider: getProviderID() ="+id);
return id; //"MySyncProvider";
}
/**
* Returns a javax.sql.RowSetReader object, which can be used to
* populate a RowSet object with data.
*/
public RowSetReader getRowSetReader() {
System.out.println("--- MySyncProvider: getRowSetReader() ---");
return new CustomRowSetReader();
}
/**
* Returns a javax.sql.RowSetWriter object, which can be used to
* write a RowSet object's data back to the underlying data source.
*/
public RowSetWriter getRowSetWriter() {
System.out.println("--- MySyncProvider: getRowSetWriter() ---");
return new CustomRowSetWriter();
}
/**
* Returns the vendor name of this SyncProvider instance
*/
public String getVendor() {
return "custom-made";
}
/**
* Returns the release version of this SyncProvider instance.
*/
public String getVersion() {
return "1.0";
}
/**
* Sets a lock on the underlying data source at the level
* indicated by datasourceLock.
*/
public void setDataSourceLock(int dataSourceLock) {
this.dataSourceLock = dataSourceLock;
}
/**
* Returns whether this SyncProvider implementation can perform
* synchronization between a RowSet object and the SQL VIEW in
* the data source from which the RowSet object got its data.
*/
public int supportsUpdatableView() {
return SyncProvider.NONUPDATABLE_VIEW_SYNC;
}
}

Instantiating a CachedRowset Object with Registered Classes

To instantiate a CachedRowSet object with registered classes, we need to pass the MySyncProvider object to a constructor of the CachedRowSetImpl class (a Sun reference implementation of the cachedRowSet interface).

CachedRowSet crs;

try {
SyncFactory.registerProvider("MySyncProvider");
Hashtable env = new Hashtable();
env.put(SyncFactory.ROWSET_SYNC_PROVIDER, "MySyncProvider");
crs = new CachedRowSetImpl(env);

Invoking CachedRowset.execute() to Load the Data

We next invoke the method CachedRowset.execute():

crs.execute(); // load data from custom RowSetReader

Invoking CachedRowset.acceptChanges() to Write the Data

Finally, we invoke CachedRowset.acceptChanges() to commit changes back to the database. I’ve provided a complete solution here. This solution puts together the steps I defined earlier to create a custom RowSet object. You have complete freedom in creating your RowSet object (you even tailor your custom RowSet’s metadata).

import java.util.Hashtable;
import java.sql.Types;
import java.sql.SQLException;
import javax.sql.RowSetReader;
import javax.sql.RowSetInternal;
import javax.sql.RowSetMetaData;
import javax.sql.rowset.RowSetMetaDataImpl;
import javax.sql.rowset.CachedRowSet;
import com.sun.rowset.CachedRowSetImpl;
import javax.sql.rowset.spi.SyncFactory;
public class DemoCustomRowSet {
CachedRowSet crs;
String stringColumn1;
String stringColumn3;
int intColumn2;
public DemoCustomRowSet() {
try {
SyncFactory.registerProvider("MySyncProvider");
Hashtable env = new Hashtable();
env.put(SyncFactory.ROWSET_SYNC_PROVIDER, "MySyncProvider");
crs = new CachedRowSetImpl(env);
crs.execute(); // load data from custom RowSetReader
System.out.println("Fetching from RowSet...");
while(crs.next()) {
displayData();
}
if(crs.isAfterLast() == true) {
System.out.println("We have reached the end");
System.out.println("crs row: " + crs.getRow());
}
System.out.println("And now backwards...");
while(crs.previous()) {
displayData();
} // end while previous
if(crs.isBeforeFirst()) {
System.out.println("We have reached the start");
}
crs.first();
if(crs.isFirst()) {
System.out.println("We have moved to first");
}
System.out.println("crs row: " + crs.getRow());
if(!crs.isBeforeFirst()) {
System.out.println("We aren't before the first row.");
}
crs.last();
if(crs.isLast()) {
System.out.println("...and now we have moved to the last");
}
System.out.println("crs row: " + crs.getRow());
if(!crs.isAfterLast()) {
System.out.println("we aren't after the last.");
}
} // end try
catch (SQLException e) {
e.printStackTrace();
System.err.println("SQLException: " + e.getMessage());
}
} // end constructor
public void displayData() throws SQLException {
stringColumn1 = crs.getString(1);
if(crs.wasNull()) {
System.out.println("stringColumn1 is null");
}
else {
System.out.println("stringColumn1: " + stringColumn1);
}
intColumn2 = crs.getInt(2);
if (crs.wasNull()) {
System.out.println("intColumn2 is null");
}
else {
System.out.println("intColumn2: " + intColumn2);
}
stringColumn3 = crs.getString(3);
if(crs.wasNull()) {
System.out.println("stringColumn3 is null");
}
else {
System.out.println("stringColumn3: " + stringColumn3);
}
} // end displayData
public static void main(String args[]) {
DemoCustomRowSet test = new DemoCustomRowSet();
}
} // end class DemoCustomRowSet



Face Book Twitter Google Plus Instagram Youtube Linkedin Myspace Pinterest Soundcloud Wikipedia

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

JDBC Topics