Source Code Cross Referenced for RowSetDataModel.java in  » IDE-Netbeans » visualweb.api.designer » com » sun » rave » faces » data » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » visualweb.api.designer » com.sun.rave.faces.data 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package com.sun.rave.faces.data;
0043:
0044:        import java.beans.Beans;
0045:        import java.sql.Connection;
0046:        import java.sql.DatabaseMetaData;
0047:        import java.sql.PreparedStatement;
0048:        import java.sql.ResultSet;
0049:        import java.sql.ResultSetMetaData;
0050:        import java.sql.SQLException;
0051:        import java.sql.Types;
0052:        import java.util.ArrayList;
0053:        import java.util.Iterator;
0054:        import java.util.List;
0055:        import java.util.Map;
0056:        import javax.faces.FacesException;
0057:        import javax.faces.context.FacesContext;
0058:        import javax.faces.model.DataModel;
0059:        import javax.faces.model.DataModelEvent;
0060:        import javax.faces.model.DataModelListener;
0061:        import javax.sql.RowSet;
0062:        import javax.sql.RowSetEvent;
0063:        import javax.sql.RowSetListener;
0064:        import com.sun.rave.faces.util.ComponentBundle;
0065:
0066:        /**
0067:         * <p>Runtime implementation of <code>javax.faces.model.DataModel</code>
0068:         * that caches retrieved database data in memory (in a session scope
0069:         * attribute of type <code>DataCache</code>), even when the underlying
0070:         * rowset is closed.</p>
0071:         *
0072:         * @author  craigmcc
0073:         */
0074:        public class RowSetDataModel extends DataModel {
0075:
0076:            // ------------------------------------------------------------ Constructors
0077:
0078:            /**
0079:             * <p>Create a new {@link RowSetDataModel} instance not connected to
0080:             * any underlying <code>RowSet</code>.</p>
0081:             */
0082:            public RowSetDataModel() {
0083:
0084:                this (null);
0085:
0086:            }
0087:
0088:            /**
0089:             * <p>Create a new {@link RowSetDataModel} instance wrapping the
0090:             * specified <code>RowSet</code>.</p>
0091:             *
0092:             * @param rowSet <code>RowSet</code> to be mapped
0093:             */
0094:            public RowSetDataModel(RowSet rowSet) {
0095:
0096:                super ();
0097:                setWrappedData(rowSet);
0098:
0099:            }
0100:
0101:            // ------------------------------------------------------ Instance Variables
0102:
0103:            /**
0104:             * <p>The number of fake data rows we will compose at
0105:             * design time.</p>
0106:             */
0107:            private static final int DESIGN_TIME_ROWS = 5;
0108:
0109:            /**
0110:             * <p>Localization resources for this package.</p>
0111:             */
0112:            private static final ComponentBundle bundle = ComponentBundle
0113:                    .getBundle(RowSetDataModel.class);
0114:
0115:            /**
0116:             * <p>List of column names for the <code>RowSet</code> we are
0117:             * currently connected to (if any).</p>
0118:             */
0119:            private List columnNames = new ArrayList();
0120:
0121:            /**
0122:             * <p>identifies whether or not the underlying database can support
0123:             * the conditonal clause used to handle nulls
0124:             * (see compooseUpdateAndDeleteStatements).</p>
0125:             */
0126:            private boolean useConditionalWhereClause = true;
0127:
0128:            /**
0129:             * <p>List of column SQL types for the <code>RowSet</code> we are
0130:             * currently connected to (if any).</p>
0131:             */
0132:            private List columnTypes = new ArrayList();
0133:
0134:            /**
0135:             * <p>List of column Java types (<code>Class</code> objects) 
0136:             * for the <code>RowSet</code> we are
0137:             * currently connected to (if any).</p>
0138:             */
0139:            private List columnJavaTypes = new ArrayList();
0140:
0141:            /**
0142:             * <p>The {@link DataCache} containing our cached row and
0143:             * column information.  A new instance (saved in session scope)
0144:             * is created on demand if not already present.</p>
0145:             */
0146:            private DataCache dataCache = null;
0147:
0148:            /**
0149:             * <p>The session attribute key under which our
0150:             * <code>DataCache</code> instance will be stored.
0151:             */
0152:            private String dataCacheKey = null;
0153:
0154:            /**
0155:             * <p><code>RowSetListener</code> for significant events
0156:             * on the <code>RowSet</code> we are currently connected to (if any).</p>
0157:             */
0158:            private RowSetListener listener = new CachedRowSetListener();
0159:
0160:            /**
0161:             * <p>The <code>ResultSetMetaData</code> associated with the
0162:             * <code>RowSet</code> we are currently connected to (if any).</p>
0163:             */
0164:            private ResultSetMetaData metadata = null;
0165:
0166:            /**
0167:             * <p>The zero relative index of the currently positioned row,
0168:             * or -1 if we are not positioned on a row.</p>
0169:             */
0170:            private int rowIndex;
0171:
0172:            /**
0173:             * <p>The <code>RowSet</code> that we are currently connected to
0174:             * (if any).</p>
0175:             */
0176:            private RowSet rowSet = null;
0177:
0178:            /**
0179:             * <p>The schema name on which we will perform updates when committing
0180:             * changes to the database.  If specified, this will be included in the
0181:             * UPDATE statement synthesized by the <code>commit()</code> method.</p>
0182:             */
0183:            private String schemaName = null;
0184:
0185:            /**
0186:             * <p>List of schema names for the columns of the <code>RowSet</code> we are
0187:             * currently connected to (if any).</p>
0188:             */
0189:            private List schemaNames = new ArrayList();
0190:
0191:            /**
0192:             * <p>The table name on which we will perform updates when committing
0193:             * changes to the database.</p>
0194:             */
0195:            private String tableName = null;
0196:
0197:            /**
0198:             * <p>List of table names for the columns of the <code>RowSet</code> we are
0199:             * currently connected to (if any).</p>
0200:             */
0201:            private List tableNames = new ArrayList();
0202:
0203:            // -------------------------------------------------------------- Properties
0204:
0205:            /**
0206:             * <p>Return the {@link DataCache} containing our cached row and
0207:             * column data, creating one if necessary.</p>
0208:             */
0209:            public DataCache getDataCache() {
0210:
0211:                // Create a new cache if one does not already exist
0212:                Map sessionMap = FacesContext.getCurrentInstance()
0213:                        .getExternalContext().getSessionMap();
0214:                dataCache = (DataCache) sessionMap.get(getDataCacheKey());
0215:                if (dataCache == null) {
0216:                    dataCache = new DataCache();
0217:                    sessionMap.put(getDataCacheKey(), dataCache);
0218:                }
0219:                return dataCache;
0220:
0221:            }
0222:
0223:            /**
0224:             * <p>Return the session attribute key under which our {@link DataCache}
0225:             * instance will be stored.
0226:             */
0227:            public String getDataCacheKey() {
0228:
0229:                return this .dataCacheKey;
0230:
0231:            }
0232:
0233:            /**
0234:             * <p>Set the session attribute key under which our
0235:             * {@link DataCache} instance will be stored.
0236:             *
0237:             * @param dataCacheKey The new key
0238:             */
0239:            public void setDataCacheKey(String dataCacheKey) {
0240:
0241:                this .dataCacheKey = dataCacheKey;
0242:
0243:            }
0244:
0245:            /**
0246:             * <p>Return the <code>RowSet</code> we are connected with,
0247:             * if any; otherwise, return <code>null</code>.  This is a
0248:             * type=safe alias for <code>getWrappedData()</code>.</p>
0249:             */
0250:            public RowSet getRowSet() {
0251:
0252:                return ((RowSet) getWrappedData());
0253:
0254:            }
0255:
0256:            /**
0257:             * <p>Set the <code>RowSet</code> we are connected with,
0258:             * or pass <code>null</code> to disconnect.  This is a
0259:             * type-safe alias for <code>setWrappedData()</code>.</p>
0260:             *
0261:             * @param rowSet The <code>RowSet</code> we are connected to,
0262:             *  or <code>null</code> to disconnect
0263:             */
0264:            public void setRowSet(RowSet rowSet) {
0265:
0266:                setWrappedData(rowSet);
0267:
0268:            }
0269:
0270:            /**
0271:             * <p>Return the name of the database schema containing the table
0272:             * we will update when <code>commit()</code> is called.</p>
0273:             */
0274:            public String getSchemaName() {
0275:
0276:                return this .schemaName;
0277:
0278:            }
0279:
0280:            /**
0281:             * <p>Set the name of the database schema containing the table
0282:             * we will update when <code>commit()</code> is called.</p>
0283:             *
0284:             * @param schemaName The schema name to be updated
0285:             */
0286:            public void setSchemaName(String schemaName) {
0287:
0288:                this .schemaName = schemaName;
0289:
0290:            }
0291:
0292:            /**
0293:             * <p>Return the name of the database table we will update when
0294:             * <code>commit()</code> is called.</p>
0295:             */
0296:            public String getTableName() {
0297:
0298:                return this .tableName;
0299:
0300:            }
0301:
0302:            /**
0303:             * <p>Set the name of the database table we will update when
0304:             * <code>commit()</code> is called.</p>
0305:             *
0306:             * @param tableName The table name to be updated
0307:             */
0308:            public void setTableName(String tableName) {
0309:
0310:                this .tableName = tableName;
0311:
0312:            }
0313:
0314:            // --------------------------------------------------------- Public Methods
0315:
0316:            /**
0317:             * <p>Clear any cached row-specific data.  This method may be called by
0318:             * application logic when it is known that the next page to be processed
0319:             * will not involve the <code>RowSet</code> we are connected to, or
0320:             * when the application wants to refresh the cached data to reflect
0321:             * any changes on the underlying database contents.</p>
0322:             *
0323:             * <p><strong>NOTE</strong> - Calling <code>execute()</code> on this
0324:             * <code>RowSetDataModel</code> will implicitly call <code>clear()</code>
0325:             * for you.</p>
0326:             */
0327:            public void clear() {
0328:
0329:                // System.out.println("RSDM: clear()");
0330:                getDataCache().clear();
0331:
0332:            }
0333:
0334:            /**
0335:             * <p>Push any deleted or updated cached rows to the specified table,
0336:             * then call <code>commit()</code> on the JDBC <code>Connection</code>
0337:             * underlying our current <code>RowSet</code>, as well as our associated
0338:             * <code>DataCache</code>.  If any <code>SQLException</code> occurs, call
0339:             * <code>rollback()</code> on the <code>Connection()</code> and
0340:             * <code>reset()</code> on the <code>DataCache</code>.</p>
0341:             *
0342:             * @exception IllegalArgumentException if the <code>tableName</code>
0343:             *  property has not yet been set
0344:             * @exception IllegalStateException if this method is called when
0345:             *  not connected to an underlying rowset
0346:             * @exception SQLException if an error occurs while committing
0347:             */
0348:            public void commit() throws SQLException {
0349:
0350:                // System.out.println("RSDM: commit()");
0351:
0352:                // Validate our preconditions
0353:                if (tableName == null) {
0354:                    throw new IllegalArgumentException(bundle
0355:                            .getMessage("noTableName")); // NOI18N
0356:                }
0357:                if (!connected()) {
0358:                    throw new IllegalStateException(bundle
0359:                            .getMessage("notConnected")); // NOI18N
0360:                }
0361:
0362:                // Local variables for resources we will need
0363:                Connection conn = null;
0364:                SQLException exception = null;
0365:                PreparedStatement ustmt = null;
0366:                PreparedStatement dstmt = null;
0367:                String extracted = null; // Table name extracted from command
0368:                List names = null; // Column names extracted from DBMD
0369:
0370:                // Acquire the JDBC resources we will need
0371:                try {
0372:
0373:                    // Extract a table name from the command if we do not have
0374:                    // one (because JDBC metadata did not include it).
0375:                    if ((getTableName() == null)
0376:                            || (getTableName().length() < 1)) {
0377:                        extracted = extract(getRowSet().getCommand());
0378:                    }
0379:
0380:                    // Acquire the Connection we will be using
0381:                    try {
0382:                        conn = getRowSet().getStatement().getConnection();
0383:                    } catch (NullPointerException e) {
0384:                        exception = new SQLException(bundle
0385:                                .getMessage("noConnection"));
0386:                        throw new FacesException(exception);
0387:                    }
0388:
0389:                    // Retrieve the database metadata for this connection
0390:                    DatabaseMetaData dbmd = conn.getMetaData();
0391:
0392:                    // Set useConditionalWhereClause based on driver
0393:                    String driverName = dbmd.getDriverName();
0394:                    if (driverName != null && driverName.equals("DB2")) { // NOI18N
0395:                        useConditionalWhereClause = false;
0396:                    } else {
0397:                        useConditionalWhereClause = true;
0398:                    }
0399:
0400:                    // Always get column names that match the table, else we have no way
0401:                    // to throw away columns not in this table (if the driver does not
0402:                    // provide the tablename in ResultSetMetaData
0403:                    names = columns(dbmd, (extracted != null) ? extracted
0404:                            : getTableName(), columnNames);
0405:
0406:                    String[] statements = composeStatements(extracted, names,
0407:                            useConditionalWhereClause, null);
0408:                    ustmt = conn.prepareStatement(statements[0]);
0409:                    dstmt = conn.prepareStatement(statements[1]);
0410:                } catch (SQLException e) {
0411:
0412:                    exception = e;
0413:
0414:                }
0415:
0416:                // Scan cached rows, performing deletes and updates as needed
0417:                try {
0418:
0419:                    if (exception == null) {
0420:                        Iterator keys = getDataCache().iterator();
0421:                        while (keys.hasNext()) {
0422:                            Integer key = (Integer) keys.next();
0423:                            DataCache.Row row = getDataCache().get(
0424:                                    key.intValue());
0425:                            DataCache.Column columns[] = row.getColumns();
0426:                            if (row.isDeleted()) {
0427:                                PreparedStatement tmpStmt = dstmt;
0428:                                boolean requiresCustomDeleteStatement = false;
0429:                                int dindex = 1;
0430:                                if (useConditionalWhereClause) {
0431:                                    // Delete this row in the database
0432:                                    // System.out.println("RSDM: delete " + row);
0433:                                    for (int i = 0; i < columns.length; i++) {
0434:                                        if (match(i, names)) {
0435:                                            // each column is set twice, see composeStatements
0436:                                            tmpStmt.setObject(dindex++,
0437:                                                    columns[i].getOriginal(),
0438:                                                    columns[i].getSqlType());
0439:                                            tmpStmt.setObject(dindex++,
0440:                                                    columns[i].getOriginal(),
0441:                                                    columns[i].getSqlType());
0442:                                        }
0443:                                    }
0444:                                } else {
0445:                                    /*
0446:                                     * First, let's see if we can use the PreparedStatement or not.
0447:                                     * If the original values contain a null, we cannot use it since
0448:                                     * WHERE column-name = null does not work.  We'll need to prepare
0449:                                     * another statement that contains column-name IS NULL for all
0450:                                     * columns that are null
0451:                                     */
0452:                                    for (int i = 0; i < columns.length; i++) {
0453:                                        if (match(i, names)) {
0454:                                            if (columns[i].getOriginal() == null) {
0455:                                                requiresCustomDeleteStatement = true;
0456:                                                break;
0457:                                            }
0458:                                        }
0459:                                    }
0460:                                    if (requiresCustomDeleteStatement) {
0461:                                        tmpStmt = conn
0462:                                                .prepareStatement(composeStatements(
0463:                                                        extracted, names,
0464:                                                        false, columns)[1]);
0465:                                    }
0466:                                    for (int i = 0; i < columns.length; i++) {
0467:                                        if (match(i, names)) {
0468:                                            if (columns[i].getOriginal() != null) {
0469:                                                tmpStmt.setObject(dindex++,
0470:                                                        columns[i]
0471:                                                                .getOriginal());
0472:                                            }
0473:                                        }
0474:                                    }
0475:                                }
0476:                                int dresult = tmpStmt.executeUpdate();
0477:                                if (requiresCustomDeleteStatement) {
0478:                                    try {
0479:                                        tmpStmt.close();
0480:                                    } catch (SQLException e) {
0481:                                        // We'll do nothing if we can't close the statement
0482:                                    }
0483:                                }
0484:                                if (dresult < 1) {
0485:                                    exception = new SQLException(bundle
0486:                                            .getMessage("deleteFailedMissing",
0487:                                                    key)); // NOI18N
0488:                                    break;
0489:                                } else if (dresult > 1) {
0490:                                    exception = new SQLException(bundle
0491:                                            .getMessage("deleteFailedMultiple",
0492:                                                    key)); // NOI18N
0493:                                    break;
0494:                                }
0495:                            } else if (row.isUpdated()) {
0496:                                PreparedStatement tmpStmt = ustmt;
0497:                                boolean requiresCustomUpdateStatement = false;
0498:                                if (!useConditionalWhereClause) {
0499:                                    /*
0500:                                     * First, let's see if we can use the PreparedStatement or not.
0501:                                     * If the original values contain a null, we cannot use it since
0502:                                     * WHERE column-name = null does not work.  We'll need to prepare
0503:                                     * another statement that contains column-name IS NULL for all
0504:                                     * columns that are null
0505:                                     */
0506:                                    for (int i = 0; i < columns.length; i++) {
0507:                                        if (match(i, names)) {
0508:                                            if (columns[i].getOriginal() == null) {
0509:                                                requiresCustomUpdateStatement = true;
0510:                                                break;
0511:                                            }
0512:                                        }
0513:                                    }
0514:                                    if (requiresCustomUpdateStatement) {
0515:                                        tmpStmt = conn
0516:                                                .prepareStatement(composeStatements(
0517:                                                        extracted, names,
0518:                                                        false, columns)[0]);
0519:                                    }
0520:                                }
0521:                                // Update this row in the database
0522:                                // System.out.println("RSDM: update " + row);
0523:                                int uindex = 1;
0524:                                for (int i = 0; i < columns.length; i++) {
0525:                                    if (match(i, names)) {
0526:                                        tmpStmt.setObject(uindex++, columns[i]
0527:                                                .getValue(), columns[i]
0528:                                                .getSqlType());
0529:                                    }
0530:                                }
0531:                                // Where clause
0532:                                if (useConditionalWhereClause) {
0533:                                    for (int i = 0; i < columns.length; i++) {
0534:                                        if (match(i, names)) {
0535:                                            /*
0536:                                             * This is the where clause, so we set every column
0537:                                             * twice, see composeStatements
0538:                                             */
0539:                                            tmpStmt.setObject(uindex++,
0540:                                                    columns[i].getOriginal(),
0541:                                                    columns[i].getSqlType());
0542:                                            tmpStmt.setObject(uindex++,
0543:                                                    columns[i].getOriginal(),
0544:                                                    columns[i].getSqlType());
0545:                                        }
0546:                                    }
0547:                                } else {
0548:                                    /*
0549:                                     * This is the where clause, we only set the property if the
0550:                                     * column is non-null.  If it is null, a custom PreparedStatement
0551:                                     * was created with the "<column-name> IS NULL" syntax.
0552:                                     */
0553:                                    for (int i = 0; i < columns.length; i++) {
0554:                                        if (match(i, names)) {
0555:                                            if (columns[i].getOriginal() != null) {
0556:                                                ustmt.setObject(uindex++,
0557:                                                        columns[i]
0558:                                                                .getOriginal());
0559:                                            }
0560:                                        }
0561:                                    }
0562:                                }
0563:                                int uresult = tmpStmt.executeUpdate();
0564:                                if (requiresCustomUpdateStatement) {
0565:                                    try {
0566:                                        tmpStmt.close();
0567:                                    } catch (SQLException e) {
0568:                                        // We'll do nothing if we can't close the statement
0569:                                    }
0570:                                }
0571:                                if (uresult < 1) {
0572:                                    exception = new SQLException(bundle
0573:                                            .getMessage("updateFailedMissing",
0574:                                                    key)); // NOI18N
0575:                                    break;
0576:                                } else if (uresult > 1) {
0577:                                    exception = new SQLException(bundle
0578:                                            .getMessage("updateFailedMultiple",
0579:                                                    key)); // NOI18N
0580:                                    break;
0581:                                }
0582:                            }
0583:                        }
0584:                    }
0585:
0586:                } catch (SQLException e) {
0587:
0588:                    exception = e;
0589:
0590:                }
0591:
0592:                // Commit on the database and associated cache
0593:                try {
0594:                    if (exception == null) {
0595:                        conn.commit();
0596:                        getDataCache().commit();
0597:                    }
0598:                } catch (SQLException e) {
0599:                    exception = e;
0600:                }
0601:
0602:                // Roll back if necessary
0603:                if (exception != null) {
0604:                    try {
0605:                        conn.rollback();
0606:                    } catch (SQLException e) {
0607:                        ;
0608:                    }
0609:                    getDataCache().reset();
0610:                }
0611:
0612:                // Free allocated resources
0613:                if (ustmt != null) {
0614:                    try {
0615:                        ustmt.close();
0616:                    } catch (SQLException e) {
0617:                        ;
0618:                    }
0619:                    ustmt = null;
0620:                }
0621:                if (dstmt != null) {
0622:                    try {
0623:                        dstmt.close();
0624:                    } catch (SQLException e) {
0625:                        ;
0626:                    }
0627:                    dstmt = null;
0628:                }
0629:
0630:                // Rethrow any saved exception
0631:                if (exception != null) {
0632:                    throw exception;
0633:                }
0634:
0635:            }
0636:
0637:            /**
0638:             * <p>Clear any cached data, then re-execute the
0639:             * query for the rowset we are connected to.  <strong>WARNING</strong> -
0640:             * this method should <strong>ONLY</strong> be called when you
0641:             * have changed the query parameters for your query, or your
0642:             * application has performed other database transaction(s) on a
0643:             * different page that should be reflected in the query results.</p>
0644:             *
0645:             * @exception IllegalStateException if this method is called when
0646:             *  not connected to an underlying rowset
0647:             * @exception SQLException if an error occurs executing the rowset
0648:             */
0649:            public void execute() throws SQLException {
0650:
0651:                // System.out.println("RSDM: execute()");
0652:
0653:                // Validate our preconditions
0654:                if (!connected()) {
0655:                    throw new IllegalStateException(bundle
0656:                            .getMessage("notConnected")); // NOI18N
0657:                }
0658:
0659:                // Call clear() on the underlying cache
0660:                getDataCache().clear();
0661:
0662:                // Call execute() on the underlying rowset
0663:                getRowSet().execute();
0664:
0665:            }
0666:
0667:            /**
0668:             * <p>Reset any deleted or updated values in the cache, so that any cached
0669:             * rows no longer appear to have been modified.  This method has no
0670:             * effect on the connected rowset (if any).</p>
0671:             */
0672:            public void reset() {
0673:
0674:                // System.out.println("RSDM: reset()");
0675:                getDataCache().reset();
0676:
0677:            }
0678:
0679:            /**
0680:             * <p>Reset any deleted or updated values in the cache (as is done by
0681:             * the <code>reset()</code> method), then call <code>rollback()</code>
0682:             * on the JDBC <code>Connectino</code> underlying our current
0683:             * <code>RowSet</code>.</p>
0684:             *
0685:             * @exception IllegalStateException if this method is called when
0686:             *  not connected to an underlying rowset
0687:             * @exception SQLException if an error occurs while committing
0688:             */
0689:            public void rollback() throws SQLException {
0690:
0691:                // System.out.println("RSDM: rollback()");
0692:
0693:                // Validate our preconditions
0694:                if (!connected()) {
0695:                    throw new IllegalStateException(bundle
0696:                            .getMessage("notConnected")); // NOI18N
0697:                }
0698:
0699:                // Reset the cache
0700:                getDataCache().reset();
0701:
0702:                // Roll back the database connection
0703:                getRowSet().getStatement().getConnection().rollback();
0704:
0705:            }
0706:
0707:            /**
0708:             * <p>Set the designated parameter on the <code>RowSet</code> to which
0709:             * we are connected.  This parameter will have no effect on any currently
0710:             * selected rows; it takes effect the next time you call
0711:             * <code>execute()</codew>.</p>
0712:             *
0713:             * @param index One-relative parameter index
0714:             * @param value Value to be set
0715:             *
0716:             * @exception IllegalStateException if this method is called when
0717:             *  not connected to an underlying rowset
0718:             * @exception SQLException if an error occurs setting the parameter value
0719:             */
0720:            public void setObject(int index, Object value) throws SQLException {
0721:
0722:                // Validate our preconditions
0723:                if (!connected()) {
0724:                    throw new IllegalStateException(bundle
0725:                            .getMessage("notConnected")); // NOI18N
0726:                }
0727:
0728:                // Set the parameter value
0729:                getRowSet().setObject(index, value);
0730:
0731:            }
0732:
0733:            /**
0734:             * <p>Set the designated parameter on the <code>RowSet</code> to which
0735:             * we are connected.  This parameter will have no effect on any currently
0736:             * selected rows; it takes effect the next time you call
0737:             * <code>execute()</codew>.</p>
0738:             *
0739:             * @param index One-relative parameter index
0740:             * @param value Value to be set
0741:             * @param type Destination SQL type (as defined in <code>java.sql.Types</code>)
0742:             *
0743:             * @exception IllegalStateException if this method is called when
0744:             *  not connected to an underlying rowset
0745:             * @exception SQLException if an error occurs setting the parameter value
0746:             */
0747:            public void setObject(int index, Object value, int type)
0748:                    throws SQLException {
0749:
0750:                // Validate our preconditions
0751:                if (!connected()) {
0752:                    throw new IllegalStateException(bundle
0753:                            .getMessage("notConnected")); // NOI18N
0754:                }
0755:
0756:                // Set the parameter value
0757:                getRowSet().setObject(index, value, type);
0758:
0759:            }
0760:
0761:            /**
0762:             * <p>Set the designated parameter on the <code>RowSet</code> to which
0763:             * we are connected.  This parameter will have no effect on any currently
0764:             * selected rows; it takes effect the next time you call
0765:             * <code>execute()</codew>.</p>
0766:             *
0767:             * @param index One-relative parameter index
0768:             * @param value Value to be set
0769:             * @param type Destination SQL type (as defined in <code>java.sql.Types</code>)
0770:             * @param scale For <code>java.sql.Types.DECIMAL</code> or
0771:             *  <code>java.sql.Types.NUMERIC</code> types, the number of digits
0772:             *  after the decimal point (ignored for all other types)
0773:             *
0774:             * @exception IllegalStateException if this method is called when
0775:             *  not connected to an underlying rowset
0776:             * @exception SQLException if an error occurs setting the parameter value
0777:             */
0778:            public void setObject(int index, Object value, int type, int scale)
0779:                    throws SQLException {
0780:
0781:                // Validate our preconditions
0782:                if (!connected()) {
0783:                    throw new IllegalStateException(bundle
0784:                            .getMessage("notConnected")); // NOI18N
0785:                }
0786:
0787:                // Set the parameter value
0788:                getRowSet().setObject(index, value, type, scale);
0789:
0790:            }
0791:
0792:            // ------------------------------------------------------- DataModel Methods
0793:
0794:            /**
0795:             * <p>Return -1 to indicate that the number of rows available is
0796:             * unknown.</p>
0797:             */
0798:            public int getRowCount() {
0799:
0800:                if (Beans.isDesignTime()) {
0801:                    return DESIGN_TIME_ROWS;
0802:                }
0803:
0804:                return (-1);
0805:
0806:            }
0807:
0808:            /**
0809:             * <p>Return a <code>Map</code> representing the column values for
0810:             * the row specified by the current <code>rowIndex</code>.  The
0811:             * returned Map supports case-insensitive matching on column names,
0812:             * and records any updates to the column values for later transfer
0813:             * to the database when <code>commit()</code> is called.  It does
0814:             * not allow column names (and corresponding values) to be added
0815:             * or removed.</p>
0816:             *
0817:             * @exception IllegalArgumentException if there is no cached
0818:             *  data for the current <code>rowIndex</code>
0819:             */
0820:            public Object getRowData() {
0821:
0822:                // System.out.println("RSDM: getRowData(" + rowIndex + ") --> " + getDataCache().get(rowIndex));
0823:
0824:                DataCache.Row row = getDataCache().get(rowIndex);
0825:                if (row == null) {
0826:                    throw new IllegalArgumentException("" + rowIndex);
0827:                }
0828:                return row;
0829:
0830:            }
0831:
0832:            /**
0833:             * <p>Return the zero-relative index of the currently positioned row,
0834:             * or -1 if we are not positioned on a row.</p>
0835:             */
0836:            public int getRowIndex() {
0837:
0838:                return (rowIndex);
0839:
0840:            }
0841:
0842:            /**
0843:             * <p>Return the <code>RowSet</code> we are currently wrapping,
0844:             * if any.</p>
0845:             */
0846:            public Object getWrappedData() {
0847:
0848:                return (rowSet);
0849:
0850:            }
0851:
0852:            /**
0853:             * <p>Return <code>true</code> if there is a cache entry for the
0854:             * current <code>rowIndex</code> value.</p>
0855:             */
0856:            public boolean isRowAvailable() {
0857:
0858:                //designtime check only
0859:                if (Beans.isDesignTime()) {
0860:                    if (rowIndex < 0 || rowIndex >= DESIGN_TIME_ROWS) {
0861:                        return false;
0862:                    }
0863:                }
0864:
0865:                //designtime and runtime
0866:                if (rowIndex >= 0) {
0867:                    return getDataCache().get(rowIndex) != null;
0868:                } else {
0869:                    return false;
0870:                }
0871:
0872:            }
0873:
0874:            //to be called at designtime only as part of fix for 6333068
0875:            private boolean shouldRowBeAvailable() {
0876:                return rowIndex >= 0 && rowIndex < DESIGN_TIME_ROWS;
0877:            }
0878:
0879:            /**
0880:             * <p>Set the zero relative index for the newly positioned row, or
0881:             * set to -1 for no currently selected row.  If there is no current
0882:             * cache entry for this row, but we are currently connected, position
0883:             * the underlying <code>RowSet</code> to the corresponding one-relative
0884:             * row number, and create a new cache entry.  In addition, fire a
0885:             * <code>DataModelEvent</code> if needed, per the Javadocs for
0886:             * this method on <code>javax.faces.model.DataModel</code>.</p>
0887:             *
0888:             * @param rowIndex The row index, or -1 for no selected row
0889:             *
0890:             * @exception FacesException if an error occurs setting the row index
0891:             * @exception IllegalArgumentException if rowIndex is less than -1
0892:             */
0893:            public void setRowIndex(int rowIndex) {
0894:
0895:                // System.out.println("RSDM: setRowIndex(" + rowIndex + ")");
0896:
0897:                // Bounds check on the incoming argument
0898:                if (rowIndex < -1) {
0899:                    throw new IllegalArgumentException(bundle.getMessage(
0900:                            "invalidRowIndex", new Integer(rowIndex))); // NOI18N
0901:                }
0902:
0903:                // Update the current row index
0904:                int oldIndex = this .rowIndex;
0905:                this .rowIndex = rowIndex;
0906:
0907:                // If we are not connected, nothing else to do
0908:                if (!connected()) {
0909:                    return;
0910:                }
0911:
0912:                // Construct a new cache item if necessary
0913:                if ((rowIndex >= 0) && connected() && !Beans.isDesignTime()
0914:                        && (getDataCache().get(rowIndex) == null)) {
0915:                    DataCache.Row row = create();
0916:                    if (row != null) {
0917:                        getDataCache().add(rowIndex, row);
0918:                    }
0919:                }
0920:
0921:                // Broadcast an event to interested listeners if we changed rows
0922:                DataModelListener listeners[] = getDataModelListeners();
0923:                if ((oldIndex != rowIndex) && (listeners != null)) {
0924:                    Object rowData = null;
0925:                    if (Beans.isDesignTime()) {
0926:                        if (shouldRowBeAvailable() && !isRowAvailable()) {
0927:                            synchronize();
0928:                        }
0929:                    }
0930:                    if (isRowAvailable()) {
0931:                        rowData = getRowData();
0932:                    }
0933:                    DataModelEvent event = new DataModelEvent(this , rowIndex,
0934:                            rowData);
0935:                    int n = listeners.length;
0936:                    for (int i = 0; i < n; i++) {
0937:                        if (null != listeners[i]) {
0938:                            listeners[i].rowSelected(event);
0939:                        }
0940:                    }
0941:                }
0942:
0943:            }
0944:
0945:            /**
0946:             * <p>Set the <code>RowSet</code> wrapped by this
0947:             * <code>RowSetDataModel</code>, or <code>null</code> to disconnect
0948:             * from the previously connected <code>RowSet</code>.</p>
0949:             *
0950:             * @param rowSet <code>RowSet</code> to be wrapped, or <code>null</code>
0951:             *  to disconnect
0952:             *
0953:             * @exception ClassCastException if this object is not of the
0954:             *  correct type
0955:             */
0956:            public void setWrappedData(Object rowSet) {
0957:
0958:                if (rowSet == null) {
0959:                    disconnect();
0960:                } else {
0961:                    disconnect();
0962:                    connect((RowSet) rowSet);
0963:                }
0964:
0965:            }
0966:
0967:            // --------------------------------------------------------- Private Methods
0968:
0969:            /**
0970:             * <p>Return the subset of the specified set of column names (from the
0971:             * original query) that are part of the specified table.  This is useful
0972:             * on databases whose JDBC driver does not include column names in the
0973:             * <code>ResultSetMetaData</code>.</p>
0974:             *
0975:             * @param conn <code>Connection</code> from which we can acquire
0976:             *  database metadata
0977:             * @param extracted The table or schema.table identifier extracted
0978:             *  from our query
0979:             * @param columns List of column names included in the query (of which
0980:             *  a subset will be returned)
0981:             *
0982:             * @exception SQLException if an error occurs processing the metadata
0983:             */
0984:            private List columns(DatabaseMetaData dbmd, String extracted,
0985:                    List columns) throws SQLException {
0986:
0987:                // Set useConditionalWhereClause based on driver
0988:                String driverName = dbmd.getDriverName();
0989:                if (driverName != null && driverName.equals("DB2")) {
0990:                    useConditionalWhereClause = false;
0991:                } else {
0992:                    useConditionalWhereClause = true;
0993:                }
0994:
0995:                // Narrow our results down to the table of interest
0996:                String schemaName = null;
0997:                String tableName = extracted;
0998:                int period = tableName.lastIndexOf('.');
0999:                if (period >= 0) {
1000:                    schemaName = tableName.substring(0, period);
1001:                    tableName = tableName.substring(period + 1);
1002:                }
1003:                ResultSet trs = dbmd.getTables(null, schemaName, tableName,
1004:                        null);
1005:                // if more than one table, take first one (what else can we do?)
1006:                if (!trs.next()) {
1007:                    throw new SQLException(tableName + " not found");
1008:                }
1009:
1010:                // Retrieve the column names for the table of interest
1011:                // and save the ones that match
1012:                ResultSet crs = dbmd.getColumns(trs.getString("TABLE_CAT"), trs
1013:                        .getString("TABLE_SCHEM"), trs.getString("TABLE_NAME"),
1014:                        "%");
1015:                trs.close();
1016:                List results = new ArrayList();
1017:                int n = columns.size();
1018:                while (crs.next()) {
1019:                    String name = crs.getString("COLUMN_NAME");
1020:                    for (int i = 0; i < n; i++) {
1021:                        if (name.equalsIgnoreCase((String) columns.get(i))) {
1022:                            results.add(name);
1023:                            break;
1024:                        }
1025:                    }
1026:                }
1027:                crs.close();
1028:                return results;
1029:
1030:            }
1031:
1032:            /**
1033:             * <p>Connect ourselves to the specified new <code>RowSet</code>.</p>
1034:             *
1035:             * @param rowSet The new <code>RowSet</code> to connect to
1036:             */
1037:            private void connect(RowSet rowSet) {
1038:
1039:                this .rowSet = rowSet;
1040:                getRowSet().addRowSetListener(listener);
1041:                synchronize();
1042:
1043:            }
1044:
1045:            /**
1046:             * <p>Return <code>true</code> if we are currently connected to an
1047:             * underlying <code>RowSet</code>.</p>
1048:             */
1049:            private boolean connected() {
1050:
1051:                return (rowSet != null);
1052:
1053:            }
1054:
1055:            /**
1056:             * <p>Create and return a new {@link DataCache.Row} representing the
1057:             * row at the currently set <code>rowIndex</code>, if there is
1058:             * actually such a row in the underlying rowset.  If there is no
1059:             * such row, return <code>null</code>.  Assumes that we
1060:             * are connected, and that rowIndex is non-negative.</p>
1061:             *
1062:             * @exception FacesException if an error occurs creating this item
1063:             */
1064:            private DataCache.Row create() {
1065:
1066:                initialize();
1067:
1068:                try {
1069:
1070:                    // Position based on the current row index
1071:                    if (!getRowSet().absolute(rowIndex + 1)) { // One relative
1072:                        return (null);
1073:                    }
1074:
1075:                    // Create a CacheItem for the contents of the current row
1076:                    DataCache.Column columns[] = new DataCache.Column[columnNames
1077:                            .size()];
1078:                    for (int i = 0; i < columnNames.size(); i++) {
1079:                        columns[i] = getDataCache().createColumn(
1080:                                (String) schemaNames.get(i),
1081:                                (String) tableNames.get(i),
1082:                                (String) columnNames.get(i),
1083:                                ((Integer) columnTypes.get(i)).intValue(),
1084:                                (Class) columnJavaTypes.get(i),
1085:                                getRowSet().getObject(i + 1));
1086:                    }
1087:                    DataCache.Row row = getDataCache().createRow(columns);
1088:                    return row;
1089:
1090:                } catch (SQLException e) {
1091:                    throw new FacesException(e);
1092:                }
1093:
1094:            }
1095:
1096:            /**
1097:             * <p>Disconnect from the currently connected <code>RowSet</code>
1098:             * (if any).  If we are not currently connected, do nothing.</p>
1099:             */
1100:            private void disconnect() {
1101:
1102:                if (!connected()) {
1103:                    return;
1104:                }
1105:
1106:                getRowSet().removeRowSetListener(listener);
1107:                metadata = null;
1108:                rowSet = null;
1109:                // NOTE - leave columnNames etc. because the cache is still alive
1110:                // NOTE - leave rowIndex where it was for persistence
1111:                // (but that won't help much behind a Data Table, because
1112:                // the component will move the cursor around on its own)
1113:
1114:            }
1115:
1116:            /**
1117:             * <p>Extract and return a table (or schema.table) name from
1118:             * the specified command, which should be an SQL select statement.</p>
1119:             *
1120:             * @param command SQL command for this rowset
1121:             */
1122:            private String extract(String command) {
1123:
1124:                boolean next = false;
1125:                command = command.trim();
1126:                String word;
1127:                while (command.length() > 0) {
1128:                    int space = command.indexOf(' ');
1129:                    if (space >= 0) {
1130:                        word = command.substring(0, space).trim();
1131:                        command = command.substring(space + 1).trim();
1132:                        ;
1133:                    } else {
1134:                        word = command.trim();
1135:                        command = "";
1136:                    }
1137:                    if (next) {
1138:                        int comma = word.indexOf(',');
1139:                        if (comma >= 0) {
1140:                            word = word.substring(0, comma);
1141:                        }
1142:                        return word;
1143:                    } else if ("FROM".equalsIgnoreCase(word)) {
1144:                        next = true;
1145:                    }
1146:                }
1147:                return "";
1148:
1149:            }
1150:
1151:            /**
1152:             * <p>Execute the rowset if needed, to avoid the need
1153:             * to manually execute it, if we not at design time.</p>
1154:             */
1155:            private void initialize() {
1156:
1157:                if (Beans.isDesignTime()) {
1158:                    return;
1159:                }
1160:
1161:                RowSet rowSet = getRowSet();
1162:                try {
1163:                    if (rowSet.isBeforeFirst()) {
1164:                        try {
1165:                            rowSet.first();
1166:                        } catch (SQLException x) {
1167:                        }
1168:                    }
1169:                } catch (SQLException x1) {
1170:                    try {
1171:                        rowSet.execute();
1172:                    } catch (SQLException x2) {
1173:                        throw new FacesException(x2);
1174:                    }
1175:                }
1176:
1177:            }
1178:
1179:            /**
1180:             * <p>Return <code>true</code> if this column belongs to
1181:             * the table we will be updating during a <code>commit()</code>.
1182:             *
1183:             * @param index Zero-relative index of the column to check
1184:             * @param names Column names extracted from database metadata, or
1185:             *  <code>null</code> to check the specific column information
1186:             */
1187:            private boolean match(int index, List names) {
1188:
1189:                if (names != null) {
1190:                    String name = (String) columnNames.get(index);
1191:                    for (int i = 0; i < names.size(); i++) {
1192:                        if (name.equalsIgnoreCase((String) names.get(i))) {
1193:                            return true;
1194:                        }
1195:                    }
1196:                    return false;
1197:                }
1198:
1199:                if ((schemaName != null)
1200:                        && !schemaName.equalsIgnoreCase((String) schemaNames
1201:                                .get(index))) {
1202:                    return false;
1203:                }
1204:                if ((tableName != null)
1205:                        && !tableName.equalsIgnoreCase((String) tableNames
1206:                                .get(index))) {
1207:                    return false;
1208:                }
1209:                return true;
1210:
1211:            }
1212:
1213:            /**
1214:             * <p>Return the specified string in single quotes if it contains
1215:             * any whitespace characters, or unchanged otherwise.</p>
1216:             *
1217:             * @param value String value to be optionally quoted
1218:             */
1219:            private String quoted(String value) {
1220:                boolean required = false;
1221:                for (int i = 0; i < value.length(); i++) {
1222:                    if (Character.isWhitespace(value.charAt(i))) {
1223:                        required = true;
1224:                        break;
1225:                    }
1226:                }
1227:                if (required) {
1228:                    return '"' + value + '"';
1229:                } else {
1230:                    return value;
1231:                }
1232:            }
1233:
1234:            /**
1235:             * <p>Synchronize the metadata associated with the current
1236:             * <code>RowSet</code>.  If the set of columns has changed
1237:             * from the previous contents (if any), the cache will be
1238:             * cleared.</p>
1239:             */
1240:            private void synchronize() {
1241:
1242:                // System.out.println("RSDM: synchronize()");
1243:
1244:                // Update the column metadata, and detect any changes
1245:                boolean changed = false;
1246:                try {
1247:                    DataCache.Column previous[] = new DataCache.Column[0];
1248:                    DataCache.Row row = null;
1249:                    Iterator keys = getDataCache().iterator();
1250:                    if (keys.hasNext()) {
1251:                        row = getDataCache().get(
1252:                                ((Integer) keys.next()).intValue());
1253:                        previous = row.getColumns();
1254:                    }
1255:                    int m = previous.length;
1256:                    metadata = getRowSet().getMetaData();
1257:                    int n = metadata.getColumnCount();
1258:                    if (m != n) {
1259:                        changed = true;
1260:                    }
1261:                    columnNames.clear();
1262:                    columnTypes.clear();
1263:                    columnJavaTypes.clear();
1264:                    schemaNames.clear();
1265:                    tableNames.clear();
1266:                    for (int i = 1; i <= n; i++) {
1267:                        // Has this column changed?
1268:                        if (previous.length >= i) {
1269:                            if (!previous[i - 1].getColumnName().equals(
1270:                                    metadata.getColumnName(i))
1271:                                    || !previous[i - 1].getSchemaName().equals(
1272:                                            metadata.getSchemaName(i))
1273:                                    || !previous[i - 1].getTableName().equals(
1274:                                            metadata.getTableName(i))) {
1275:                                changed = true;
1276:                            }
1277:                        }
1278:                        // Save the new column names
1279:                        columnNames.add(metadata.getColumnName(i));
1280:                        columnTypes.add(new Integer(metadata.getColumnType(i)));
1281:                        Class javaType = null;
1282:                        try {
1283:                            String javaTypeName = metadata
1284:                                    .getColumnClassName(i);
1285:                            javaType = Class.forName(javaTypeName);
1286:                        } catch (Exception jte) {
1287:                            //let javaType be null
1288:                        }
1289:                        columnJavaTypes.add(javaType);
1290:                        schemaNames.add(metadata.getSchemaName(i));
1291:                        tableNames.add(metadata.getTableName(i));
1292:                    }
1293:                } catch (SQLException e) {
1294:                    throw new FacesException(e);
1295:                }
1296:
1297:                // If the set of columns has changed, clear the cache
1298:                if (!Beans.isDesignTime() && changed) {
1299:                    // System.out.println("RSDM: columns have changed, clear cache");
1300:                    getDataCache().clear();
1301:                }
1302:
1303:                // At design time only, cache some fake data
1304:                // with the appropriate data types
1305:                if (!Beans.isDesignTime()) {
1306:                    return;
1307:                }
1308:                for (int i = 0; i < DESIGN_TIME_ROWS; i++) {
1309:                    DataCache.Column columns[] = new DataCache.Column[columnNames
1310:                            .size()];
1311:                    for (int j = 0; j < columnNames.size(); j++) {
1312:                        String schemaName = "";
1313:                        String tableName = "";
1314:                        String columnName = (String) columnNames.get(j);
1315:                        int columnType = ((Integer) columnTypes.get(j))
1316:                                .intValue();
1317:                        Class columnJavaType = (Class) columnJavaTypes.get(j);
1318:                        Object fakeData;
1319:                        try {
1320:                            fakeData = getFakeData(metadata, columnName);
1321:                        } catch (SQLException e) {
1322:                            throw new FacesException(e);
1323:                        }
1324:                        columns[j] = getDataCache().createColumn(schemaName,
1325:                                tableName, columnName, columnType,
1326:                                columnJavaType, fakeData);
1327:                    }
1328:                    DataCache.Row row = getDataCache().createRow(columns);
1329:                    getDataCache().add(i, row);
1330:                }
1331:
1332:            }
1333:
1334:            // --------------------------------------------------------- Private Classes
1335:
1336:            /**
1337:             * <p>Listener for significant changes on the <code>RowSet</code> our
1338:             * parent is connected to.</p>
1339:             */
1340:            private class CachedRowSetListener implements  RowSetListener {
1341:
1342:                public void cursorMoved(RowSetEvent event) {
1343:                    ; // No action required
1344:                }
1345:
1346:                public void rowChanged(RowSetEvent event) {
1347:                    ; // No action required
1348:                }
1349:
1350:                public void rowSetChanged(RowSetEvent event) {
1351:                    // System.out.println("RSDM: rowSetChanged()");
1352:                    RowSetDataModel.this .synchronize();
1353:                }
1354:
1355:            }
1356:
1357:            // -------------------------------------------------- Private Static Methods
1358:
1359:            /**
1360:             * <p>Return fake data of the appropriate type for use at design time.
1361:             * (Snarfed from <code>ResultSetPropertyResolver</code>).</p>
1362:             */
1363:            private static Object getFakeData(ResultSetMetaData rsmd,
1364:                    String colName) throws SQLException {
1365:
1366:                int colIndex = -1;
1367:                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
1368:                    if (rsmd.getColumnName(i).equals(colName)) {
1369:                        colIndex = i;
1370:                        break;
1371:                    }
1372:                }
1373:                switch (rsmd.getColumnType(colIndex)) {
1374:                case Types.ARRAY:
1375:                    return new java.sql.Array() {
1376:                        public Object getArray() {
1377:                            return null;
1378:                        }
1379:
1380:                        public Object getArray(long index, int count) {
1381:                            return null;
1382:                        }
1383:
1384:                        public Object getArray(long index, int count, Map map) {
1385:                            return null;
1386:                        }
1387:
1388:                        public Object getArray(Map map) {
1389:                            return null;
1390:                        }
1391:
1392:                        public int getBaseType() {
1393:                            return Types.CHAR;
1394:                        }
1395:
1396:                        public String getBaseTypeName() {
1397:                            return "CHAR"; //NOI18N
1398:                        }
1399:
1400:                        public ResultSet getResultSet() {
1401:                            return null;
1402:                        }
1403:
1404:                        public ResultSet getResultSet(long index, int count) {
1405:                            return null;
1406:                        }
1407:
1408:                        public ResultSet getResultSet(long index, int count,
1409:                                Map map) {
1410:                            return null;
1411:                        }
1412:
1413:                        public ResultSet getResultSet(Map map) {
1414:                            return null;
1415:                        }
1416:
1417:                        public void free() {
1418:                        }
1419:                    };
1420:                case Types.BIGINT:
1421:
1422:                    //return new Long(rowIndex);
1423:                    return new Long(123);
1424:                case Types.BINARY:
1425:                    return new byte[] { 1, 2, 3, 4, 5 };
1426:                case Types.BIT:
1427:                    return new Boolean(true);
1428:                case Types.BLOB:
1429:                    return new javax.sql.rowset.serial.SerialBlob(new byte[] {
1430:                            1, 2, 3, 4, 5 });
1431:                case Types.BOOLEAN:
1432:                    return new Boolean(true);
1433:                case Types.CHAR:
1434:
1435:                    //return new String(colName + rowIndex);
1436:                    return new String(bundle.getMessage("arbitraryCharData")); //NOI18N
1437:                case Types.CLOB:
1438:                    return new javax.sql.rowset.serial.SerialClob(bundle
1439:                            .getMessage("arbitraryClobData").toCharArray());
1440:                case Types.DATALINK:
1441:                    try {
1442:                        return new java.net.URL("http://www.sun.com"); //NOI18N
1443:                    } catch (java.net.MalformedURLException e) {
1444:                        return null;
1445:                    }
1446:                case Types.DATE:
1447:                    return new java.sql.Date(new java.util.Date().getTime());
1448:                case Types.DECIMAL:
1449:                    return new java.math.BigDecimal(java.math.BigInteger.ONE);
1450:                case Types.DISTINCT:
1451:                    return null;
1452:                case Types.DOUBLE:
1453:
1454:                    //return new Double(rowIndex);
1455:                    return new Double(123);
1456:                case Types.FLOAT:
1457:
1458:                    //return new Double(rowIndex);
1459:                    return new Double(123);
1460:                case Types.INTEGER:
1461:
1462:                    //return new Integer(rowIndex);
1463:                    return new Integer(123);
1464:                case Types.JAVA_OBJECT:
1465:
1466:                    //return new String(colName + "_" + rowIndex);  //NOI18N
1467:                    return new String(bundle.getMessage("arbitraryCharData")); //NOI18N
1468:                case Types.LONGVARBINARY:
1469:                    return new byte[] { 1, 2, 3, 4, 5 };
1470:                case Types.LONGVARCHAR:
1471:
1472:                    //return new String(colName + "_" + rowIndex); //NOI18N
1473:                    return new String(bundle.getMessage("arbitraryCharData")); //NOI18N
1474:                case Types.NULL:
1475:                    return null;
1476:                case Types.NUMERIC:
1477:                    return new java.math.BigDecimal(java.math.BigInteger.ONE);
1478:                case Types.OTHER:
1479:                    return null;
1480:                case Types.REAL:
1481:
1482:                    //return new Float(rowIndex);
1483:                    return new Float(123);
1484:                case Types.REF:
1485:                    return new java.sql.Ref() {
1486:                        private Object data = new String(bundle
1487:                                .getMessage("arbitraryCharData")); //NOI18N
1488:
1489:                        public String getBaseTypeName() {
1490:                            return "CHAR"; //NOI18N
1491:                        }
1492:
1493:                        public Object getObject() {
1494:                            return data;
1495:                        }
1496:
1497:                        public Object getObject(Map map) {
1498:                            return data;
1499:                        }
1500:
1501:                        public void setObject(Object value) {
1502:                            data = value;
1503:                        }
1504:                    };
1505:                case Types.SMALLINT:
1506:
1507:                    //return new Short((short)rowIndex);
1508:                    return new Short((short) 123);
1509:                case Types.STRUCT:
1510:                    return new java.sql.Struct() {
1511:                        private String[] data = {
1512:                                bundle.getMessage("arbitraryCharData"),
1513:                                bundle.getMessage("arbitraryCharData2"),
1514:                                bundle.getMessage("arbitraryCharData3") }; //NOI18N
1515:
1516:                        public Object[] getAttributes() {
1517:                            return data;
1518:                        }
1519:
1520:                        public Object[] getAttributes(Map map) {
1521:                            return data;
1522:                        }
1523:
1524:                        public String getSQLTypeName() {
1525:                            return "CHAR"; //NOI18N
1526:                        }
1527:                    };
1528:                case Types.TIME:
1529:                    return new java.sql.Time(new java.util.Date().getTime());
1530:                case Types.TIMESTAMP:
1531:                    return new java.sql.Timestamp(new java.util.Date()
1532:                            .getTime());
1533:                case Types.TINYINT:
1534:
1535:                    //return new Byte((byte)rowIndex);
1536:                    return new Byte((byte) 123);
1537:                case Types.VARBINARY:
1538:                    return new byte[] { 1, 2, 3, 4, 5 };
1539:                case Types.VARCHAR:
1540:
1541:                    //return new String(colName + "_" + rowIndex); //NOI18N
1542:                    return new String(bundle.getMessage("arbitraryCharData")); //NOI18N
1543:                }
1544:                return null;
1545:            }
1546:
1547:            /**
1548:             * <p>Compose update and delete statements.  This method returns an array of 2 Strings,
1549:             * the first being an update statement and the second being a delete statement.
1550:             *
1551:             * If useConditionalWhereClause is true, the statements are composed in such a way that
1552:             * they will work even if some columns are null.  This is accomplished by checking for
1553:             * null in the where clause.  As a consequence of this, the column parameter in the where
1554:             * clause must be set twice.
1555:             * For example:
1556:             * UPDATE table 1
1557:             * SET col1 = ?, col2 = ?
1558:             * WHERE ((? IS NULL AND col1 IS NULL) OR col1 = ?)
1559:             * AND   ((? IS NULL AND col2 IS NULL) OR col2 = ?)
1560:             *
1561:             * If useConditionalWhereClause is false, when called with null as the value of the
1562:             * columns argument, these returned statements will be the "standard" statements that
1563:             * are prepared and used for all rows where no original values are null.  When called
1564:             * with a non-null columns argument, this method returns statements that correctly deal
1565:             * with null values in the where clause (that is, the where caluse contains a
1566:             * "<column-name> IS NULL"
1567:             */
1568:            private String[] composeStatements(String extracted, List names,
1569:                    boolean useConditionalWhereClause,
1570:                    DataCache.Column[] columns) {
1571:
1572:                // Construct the delete and update statements we will be using
1573:                StringBuffer dsb = new StringBuffer("DELETE FROM "); // NOI18N
1574:                if (extracted != null) {
1575:                    dsb.append(extracted);
1576:                } else {
1577:                    if ((getSchemaName() != null)
1578:                            && (getSchemaName().length() > 0)) {
1579:                        dsb.append(quoted(getSchemaName()));
1580:                        dsb.append("."); // NOI18N
1581:                    }
1582:                    dsb.append(quoted(getTableName()));
1583:                }
1584:
1585:                StringBuffer usb = new StringBuffer("UPDATE "); // NOI18N
1586:                if (extracted != null) {
1587:                    usb.append(extracted);
1588:                } else {
1589:                    if ((getSchemaName() != null)
1590:                            && (getSchemaName().length() > 0)) {
1591:                        usb.append(quoted(getSchemaName()));
1592:                        usb.append("."); // NOI18N
1593:                    }
1594:                    usb.append(quoted(getTableName()));
1595:                }
1596:
1597:                usb.append(" SET "); // NOI18N
1598:                int m = 0; // included columns
1599:                int n = columnNames.size();
1600:                for (int i = 0; i < n; i++) {
1601:                    if (!match(i, names)) {
1602:                        continue;
1603:                    }
1604:                    if (m > 0) {
1605:                        usb.append(", "); // NOI18N
1606:                    }
1607:                    usb.append(quoted((String) columnNames.get(i)));
1608:                    usb.append(" = ?"); // NOI18N
1609:                    m++;
1610:                }
1611:
1612:                dsb.append(" WHERE "); // NOI18N
1613:                usb.append(" WHERE "); // NOI18N
1614:                m = 0;
1615:                for (int i = 0; i < n; i++) {
1616:                    if (!match(i, names)) {
1617:                        continue;
1618:                    }
1619:                    if (m > 0) {
1620:                        dsb.append(" AND "); // NOI18N
1621:                        usb.append(" AND "); // NOI18N
1622:                    }
1623:                    if (useConditionalWhereClause) {
1624:                        dsb.append("((? IS NULL AND ");
1625:                        usb.append("((? IS NULL AND ");
1626:                        dsb.append(quoted((String) columnNames.get(i)));
1627:                        usb.append(quoted((String) columnNames.get(i)));
1628:                        dsb.append(" IS NULL) OR ");
1629:                        usb.append(" IS NULL) OR ");
1630:                        dsb.append(quoted((String) columnNames.get(i)));
1631:                        usb.append(quoted((String) columnNames.get(i)));
1632:                        dsb.append(" = ?)");
1633:                        usb.append(" = ?)");
1634:                    } else if (columns != null
1635:                            && columns[i].getOriginal() == null) {
1636:                        dsb.append(quoted((String) columnNames.get(i)));
1637:                        usb.append(quoted((String) columnNames.get(i)));
1638:                        dsb.append(" IS NULL"); // NOI18N
1639:                        usb.append(" IS NULL"); // NOI18N
1640:                    } else {
1641:                        dsb.append(quoted((String) columnNames.get(i)));
1642:                        usb.append(quoted((String) columnNames.get(i)));
1643:                        dsb.append(" = ?"); // NOI18N
1644:                        usb.append(" = ?"); // NOI18N
1645:                    }
1646:
1647:                    m++;
1648:                }
1649:
1650:                String[] statements = new String[2];
1651:                statements[0] = usb.toString();
1652:                statements[1] = dsb.toString();
1653:                //System.out.println("RSDM: " + ((columns == null)? "standard": "custom") + " update: " + statements[0]); //NOI18N
1654:                //System.out.println("RSDM: " + ((columns == null)? "standard": "custom") + " delete: " + statements[1]); //NOI18N
1655:
1656:                return statements;
1657:            }
1658:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.