Review Page - use this page to add your comments for this spec.
This is the page describing the functional changes and underlying design of migrating the visualweb project's use of a private implementation of rowsets to using the reference implementation that comes with the Java Runtime Environment.
This task is tracked by Issue 94906 in Issuezilla
Today the Visual Web project (VWP) uses a private extension of the standard Java rowset functionality. This is a problem because
Our goal is to migrate VWP to using the standard RowSet interfaces and the RowSet RI. This involves not only fixing VWP to use the standard; it also means somehow migrating or otherwise supporting existing VWP and Java Studio Creator customers who have built their applications using the proprietary VWP rowset implementation.
This section provides a description of the changes in VWP that are visible to the NetBeans user.
For each use case I will describe the existing behavior and what will change when we move to standard rowsets.
I will also address support of existing customers if that is relevant to the use case.
Today when a user drags a database table onto a visual component, a CachedRowSetDataProvider is created in the Page Bean for the page and an instance of com.sun.sql.rowset.CachedRowSetXImpl is added to the session bean as a private member variable.
This rowset is constructed where it is declared:
private CachedRowSetXImpl personRowSet = new CachedRowSetXImpl();
CachedRowSetXImpl is imported in the Session Bean as follows:
import com.sun.sql.rowset.CachedRowSetXImpl;
In the _init() method of the bean the rowset is initialized as follows:
personRowSet.setDataSourceName("java:comp/env/jdbc/TravelPack");
personRowSet.setCommand("SELECT * FROM TRAVEL.PERSON");
personRowSet.setTableName("PERSON");
This rowset is also exposed as a property by defining a setter and getter for the rowset:
public CachedRowSetXImpl getPersonRowSet() {
return personRowSet;
}
public void setPersonRowSet(CachedRowSetXImpl crsxi) {
this.personRowSet = crsxi;
}
The new functionality will be very similar, with some small but important changes
The import statement in the session bean will change to:
import com.sun.rowset.CachedRowSetImpl;
The declaration of the rowset in the Session Bean will change as follows:
private CachedRowSet personRowSet = CachedRowSetDataProvider.createCachedRowSet();
The createCachedRowSet}} method of {{{CachedRowSetDataProvider is a new public static method that would look like this:
public static CachedRowSet createCachedRowSet() {
try {
return new CachedRowSetImpl();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
The reason this method exists is to catch and re-throw the SQLException as a RuntimeException. If we were to call the CachedRowSetImpl method directly where the variable is declared we would get a compilation error because the exception is not being handled.
We will need to import CachedRowSetDataProvider into the bean where the rowset is generated:
import com.sun.data.provider.impl.CachedRowSetDataProvider;
Finally, the property getter/setter pair for the rowset will also change:
public CachedRowSet getPersonRowSet() {
return personRowSet;
}
public void setPersonRowSet(CachedRowSet crs) {
this.personRowSet = crs;
}
NOTE that the type of the variable is not the implementation class but the interface. This is very important, as it by default requires any code that uses the rowset to stick with the standard interface methods. This is an important principle: we want our user code to be standards-compliant, and not make use of proprietary extensions, even if those extensions are part of the RI.
When an existing project is opened in NetBeans 6, we will detect this and mark the project as using the old rowsets. Depending on how our issues are resolved (see Issues below), the user may need to obtain the old rowset jar from the update center.
Any new rowsets created in this project will continue to use the old rowset classes.
Only new projects will use the RI rowset.
An example of this is the MaxTripRowSet that is defined as part of the InsertUpdateDelete tutorial.
To do this, you drag a table from a connected database to any of the Pages, Application Beans, Request Beans or Session Beans that are displayed in the project navigator while you are in design view.
When you do this, a new CachedRowSetDataProvider and an associated rowset are created in that element (with the exception that if you drag a table onto a Page, the rowset is created in the session bean, while the data provider is created on the page).
In all these cases the same basic code is generated as described above: an instance of the rowset is declared, a setter/getter pair is generated for it, and it is initialized in the _init() method for the given bean.
The same changes will be made as for when the rowset is created as part of a data binding: the type for the variable and the setter/getter pair will be CachedRowSet rather than CachedRowSetXImpl.
This section describes the impact of this change to other parts of organization.
QE will need to test import of existing projects from NetBeans 5.5 and Creator 2 to make sure these existing projects can work with the RI of rowsets.
We may need to update the migration guide to provide guidance for moving code that depends on CachedRowSetX extensions to work with the reference implementation. It's possible that we will choose to wait on this until we understand better how many people are using these extensions and the level of impact -- this documentation may not be necessary.
These are described in the main VisualWeb6TaskList
There is one key piece of functionality in the Creator rowset which is not available in the RI: the ability to update and insert rows on a rowset whose command is a join of one or more tables. In the Creator rowset code, you can update the columns of the table returned by rowset.getTableName(). This is not possible in the rowset RI. There is general consensus that this is crucial functionality and we need to provide support for it. The question is, how?
Here are the various plans that have been proposed, in order of preference.
Rowsets based on a join in the RI appear to be not supported not by any particular code that disallows it but primarily by the fact that the underlying JDBC result set marks all columns as read-only when the query is a join.
Rowsets return their metadata as RowSetMetaData. For reasons that escape me, this class allows you to not only read but also modify the metadata. There is also a method RowSet.setMetaData() that allows you to set the metadata for a rowset.
With this in hand, it is potentially possible to "trick" the rowset to allow updates on the primary table by modifying the metadata to indicate the columns are updatable.
It is likely this will not work, but it's worth a shot, and will take a day to test out. I'll be reporting back at this space.
It is not clear that this will work -- it is possible that large chunks of code will need to be rewritten and will be more effort than is wortwhile.
The value of this is that it is much more clear that we can open source this solution, and also most of our code will rely on the reference implementation rather than be our own copy that we have to support. Bugfixes will be done in one place rather than two places, etc.
This is attractive because it will Just Work and no extra coding will be required. It is unattractive because we'd really like users to make use of the RI if we can.
Options that are explicitly off the table: