4860 lines · 220.4 KB · Java
RawDownload
/* * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.rowset.internal; import java.sql.*;import javax.sql.*;import java.util.*;import java.math.BigDecimal; import javax.sql.rowset.*;import javax.sql.rowset.spi.*; import com.sun.rowset.*;import java.io.IOException;import java.io.ObjectInputStream; /** * There will be two sets of data which will be maintained by the rowset at the * time of synchronization. The <code>SyncProvider</code> will utilize the * <code>SyncResolver</code> to synchronize the changes back to database. */public class SyncResolverImpl extends CachedRowSetImpl implements SyncResolver {    /**     * This CachedRowSet object will encapsulate a rowset     * which will be sync'ed with the datasource but will     * contain values in rows where there is conflict.     * For rows other than conflict, it will *not* contain     * any data. For rows containing conflict it will     * return either of the three values set by SyncResolver.*_CONFLICT     * from getStatus()     */    private CachedRowSetImpl crsRes;     /**     * This is the actual CachedRowSet object     * which is being synchronized back to     * datasource.     */    private CachedRowSetImpl crsSync;     /**     *  This ArrayList will contain the status of a row     *  from the SyncResolver.* values else it will be null.     */    private ArrayList stats;     /**     * The RowSetWriter associated with the original     * CachedRowSet object which is being synchronized.     */    private CachedRowSetWriter crw;     /**     * Row number identifier     */    private int rowStatus;     /**     * This will contain the size of the <code>CachedRowSet</code> object     */    private int sz;     /**     * The <code>Connection</code> handle used to synchronize the changes     * back to datasource. This is the same connection handle as was passed     * to the CachedRowSet while fetching the data.     */    private transient Connection con;     /**     * The <code>CachedRowSet</code> object which will encapsulate     * a row at any time. This will be built from CachedRowSet and     * SyncResolver values. Synchronization takes place on a row by     * row basis encapsulated as a CahedRowSet.     */    private CachedRowSet row;     private JdbcRowSetResourceBundle resBundle;     /**     * Public constructor     */    public SyncResolverImpl() throws SQLException {        try {            crsSync = new CachedRowSetImpl();            crsRes = new CachedRowSetImpl();            crw = new CachedRowSetWriter();            row = new CachedRowSetImpl();            rowStatus = 1;            try {                resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();            } catch(IOException ioe) {                throw new RuntimeException(ioe);            }         } catch(SQLException sqle) {        }     }      /**     * Retrieves the conflict status of the current row of this     * <code>SyncResolver</code>, which indicates the operationthe <code>RowSet</code>     * object was attempting when the conflict occurred.     *     * @return one of the following constants:     *         <code>SyncResolver.UPDATE_ROW_CONFLICT</code>,     *         <code>SyncResolver.DELETE_ROW_CONFLICT</code>, or     *         <code>SyncResolver.INSERT_ROW_CONFLICT</code>     */    public int getStatus() {        return ((Integer)stats.get(rowStatus-1)).intValue();    }     /**     * Retrieves the value in the designated column in the current row of this     * <code>SyncResolver</code> object, which is the value that caused a conflict.     *     * @param index <code>int</code> designating the column in this row of this     *        <code>SyncResolver</code> object from which to retrieve the value     *        causing a conflict     */    public Object getConflictValue(int index) throws SQLException {        try {             return crsRes.getObject(index);        } catch(SQLException sqle) {            throw new SQLException(sqle.getMessage());        }    }     /**     * Retrieves the value in the designated column in the current row of this     * <code>SyncResolver</code> object, which is the value that caused a conflict.     *     * @param columnName a <code>String</code> object designating the column in this row of this     *        <code>SyncResolver</code> object from which to retrieve the value     *        causing a conflict     */    public Object getConflictValue(String columnName) throws SQLException {        try {             return crsRes.getObject(columnName);        } catch(SQLException sqle) {             throw new SQLException(sqle.getMessage());        }    }     /**     * Sets <i>obj</i> as the value in column <i>index</i> in the current row of the     * <code>RowSet</code> object. This value is the resolved value that is to be     * persisted in the data source.     *     * @param index an <code>int</code> giving the number of the column into which to     *        set the value to be persisted     * @param obj an <code>Object</code> that is the value to be set in the data source     */    public void setResolvedValue(int index, Object obj) throws SQLException {        // modify method to throw SQLException in spec         /**         * When a value is resolved properly make it to null         * inside crsRes for that column.         *         * For more than one conflicts in the row,         * check for the last resolved value of the current row         * (Note: it can be resolved randomly for same row)         * then sync back immediately.         **/        try {            // check whether the index is in range            if(index<=0 || index > crsSync.getMetaData().getColumnCount() ) {                throw new SQLException(resBundle.handleGetObject("syncrsimpl.indexval").toString()+ index);            }             // check whether index col is in conflict            if(crsRes.getObject(index) == null) {                throw new SQLException(resBundle.handleGetObject("syncrsimpl.noconflict").toString());            }        } catch (SQLException sqle) {            // modify method to throw for SQLException            throw new SQLException(sqle.getMessage());        }        try {             boolean bool = true;             /** Check resolved value to be either of conflict               * or in rowset else throw sql exception.               * If we allow a value other than that in CachedRowSet or               * datasource we will end up in looping the loop of exceptions.              **/              if( ((crsSync.getObject(index)).toString()).equals(obj.toString()) ||                     ((crsRes.getObject(index)).toString()).equals(obj.toString()) ) {                 /**                 * Check whether this is the only conflict in the row.                 * If yes, synchronize this row back                 * which has been resolved, else wait                 * for all conflicts of current row to be resolved                 *                 * Step 1: Update crsRes and make the index col as null                 * i.e. resolved                 * crsRes.updateObject(index, obj);                 **/                  crsRes.updateNull(index);                  crsRes.updateRow();                  /**                  * Step 2: Change the value in the CachedRowSetImpl object                  * crsSync.updateObject(index, obj);                  * crsSync.updateRow();                  **/                 if(row.size() != 1) {                    row = buildCachedRow();                 }                  row.updateObject(index, obj);                 row.updateRow();                  for(int j=1; j < crsRes.getMetaData().getColumnCount(); j++) {                     if(crsRes.getObject(j) != null) {                        bool = false;                        break;                         // break out of loop and wait for other cols                         // in same row to get resolved                     } //end if                   } //end for                   if(bool) {                     /**                      * sync data back using CachedRowSetWriter                      * construct the present row and pass it to the writer                      * to write back to db.                      **/                     try {                           /**                            * Note : The use of CachedRowSetWriter to get *same* Connection handle.                            * The CachedRowSetWriter uses the connection handle                            * from the reader, Hence will use the same connection handle                            * as of original CachedRowSetImpl                            **/                           writeData(row);                           //crw.writeData( (RowSetInternal)crsRow);                          //System.out.printlnt.println("12");                      } catch(SyncProviderException spe) {                         /**                          * This will occur if db is not allowing                          * even after resolving the conflicts                          * due to some reasons.                          * Also will prevent from going into a loop of SPE's                          **/                         throw new SQLException(resBundle.handleGetObject("syncrsimpl.syncnotpos").toString());                     }                  } //end if(bool)              } else {                 throw new SQLException(resBundle.handleGetObject("syncrsimpl.valtores").toString());             } //end if (crs.getObject ...) block          } catch(SQLException sqle) {           throw new SQLException(sqle.getMessage());        }    }     /**     * This passes a CachedRowSet as a row the the CachedRowSetWriter     * after the values have been resolved, back to the datasource.     *     * @param row a <code>CachedRowSet</code> object which will hold the     *        values of a particular row after they have been resolved by     *        the user to synchronize back to datasource.     * @throws SQLException if synchronization does not happen properly     *         maybe beacuse <code>Connection</code> has timed out.     **/     private void writeData(CachedRowSet row) throws SQLException {        crw.updateResolvedConflictToDB(row, crw.getReader().connect((RowSetInternal)crsSync));     }     /**     * This function builds a row  as a <code>CachedRowSet</code> object     * which has been resolved and is ready to be synchrinized to the datasource     *     * @throws SQLException if there is problem in building     *         the metadata of the row.     **/     private CachedRowSet buildCachedRow() throws SQLException {       int iColCount;       CachedRowSetImpl crsRow = new CachedRowSetImpl();        RowSetMetaDataImpl rsmd = new RowSetMetaDataImpl();       RowSetMetaDataImpl rsmdWrite = (RowSetMetaDataImpl)crsSync.getMetaData();       RowSetMetaDataImpl rsmdRow = new RowSetMetaDataImpl();        iColCount = rsmdWrite.getColumnCount();       rsmdRow.setColumnCount(iColCount);        for(int i =1;i<=iColCount;i++) {          rsmdRow.setColumnType(i,rsmdWrite.getColumnType(i));          rsmdRow.setColumnName(i,rsmdWrite.getColumnName(i));          rsmdRow.setNullable(i,ResultSetMetaData.columnNullableUnknown);           try {             rsmdRow.setCatalogName(i, rsmdWrite.getCatalogName(i));             rsmdRow.setSchemaName(i, rsmdWrite.getSchemaName(i));          } catch(SQLException e) {               e.printStackTrace();          }        } //end for        crsRow.setMetaData(rsmdRow);        crsRow.moveToInsertRow();        for(int col=1;col<=crsSync.getMetaData().getColumnCount();col++) {           crsRow.updateObject(col, crsSync.getObject(col));       }        crsRow.insertRow();       crsRow.moveToCurrentRow();        crsRow.absolute(1);       crsRow.setOriginalRow();       try {          crsRow.setUrl(crsSync.getUrl());      } catch(SQLException sqle) {       }       try {          crsRow.setDataSourceName(crsSync.getCommand());       } catch(SQLException sqle) {        }        try {           if(crsSync.getTableName()!= null){              crsRow.setTableName(crsSync.getTableName());           }        } catch(SQLException sqle) {         }        try {            if(crsSync.getCommand() != null)                crsRow.setCommand(crsSync.getCommand());       } catch(SQLException sqle) {        }        try {            crsRow.setKeyColumns(crsSync.getKeyColumns());       } catch(SQLException sqle) {        }       return crsRow;    }       /**     * Sets <i>obj</i> as the value in column <i>columnName</i> in the current row of the     * <code>RowSet</code> object. This value is the resolved value that is to be     * persisted in the data source.     *     * @param columnName a <code>String</code> object giving the name of the column     *        into which to set the value to be persisted     * @param obj an <code>Object</code> that is the value to be set in the data source     */    public void setResolvedValue(String columnName, Object obj) throws SQLException {       // modify method to throw SQLException in spec       // %%% Missing implementation!    }     /**     * This function is package private,     * i.e. cannot be accesses outside this package.     * This is used to set the actual CachedRowSet     * which is being synchronized to the database     **/   void setCachedRowSet(CachedRowSet crs) {           crsSync = (CachedRowSetImpl)crs;    }     /**     * This function is package private,     * i.e. cannot be accesses outside this package.     * This is used to set the CachedRowSet formed     * with conflict values.     **/    void setCachedRowSetResolver(CachedRowSet crs){         try {              crsRes = (CachedRowSetImpl)crs;              crsRes.afterLast();              sz = crsRes.size();         } catch (SQLException sqle) {            // do nothing         }    }     /**     * This function is package private,     * i.e. cannot be accesses outside this package.     * This is used to set the status of each row     * to either of the values SyncResolver.*_CONFLICT     **/    void setStatus(ArrayList status){             stats = status;    }     /**     * This function is package private,     * i.e. cannot be accesses outside this package.     * This is used to set the handle to the writer object     * which will write the resolved values back to datasource     **/    void setCachedRowSetWriter(CachedRowSetWriter CRWriter) {         crw = CRWriter;    }     /**     * Moves the cursor down one row from its current position. A <code>SyncResolver</code>     * cursor is initially positioned before the first conflict row; the first call to the     * method <code>nextConflict()</code> makes the first conflict row the current row;     * the second call makes the second conflict row the current row, and so on.     * <p>     * If an input stream is open for the current row, a call to the method next will     * implicitly close it. A <code>SyncResolver</code> object's warning chain is cleared     * when a new row     *     * @return true if the new current row is valid; false if there are no more rows     * @throws SQLException if a database access occurs     *     */    public boolean nextConflict() throws SQLException {        /**          * The next() method will hop from          * one conflict to another          *          * Internally do a crs.next() until          * next conflict.          **/      boolean bool = false;       crsSync.setShowDeleted(true);      while(crsSync.next()) {           crsRes.previous();           rowStatus++;  //sz--;           if((rowStatus-1) >= stats.size()) {             bool = false;             break;          }           if(((Integer)stats.get(rowStatus-1)).intValue() == SyncResolver.NO_ROW_CONFLICT) {              // do nothing              // bool remains as false             ;           } else {             bool = true;             break;           } //end if       } //end while         crsSync.setShowDeleted(false);        return bool;   } // end next() method      /**     * Moves the cursor to the previous conflict row in this <code>SyncResolver</code> object.     *     * @return <code>true</code> if the cursor is on a valid row; <code>false</code>     *     if it is off the result set

Lines 1–500 of 4860.