Source Code Cross Referenced for JDBCPersistentMap.java in  » Workflow-Engines » wfmopen-2.1.1 » de » danet » an » util » persistentmaps » 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 » Workflow Engines » wfmopen 2.1.1 » de.danet.an.util.persistentmaps 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * This file is part of the WfMOpen project.
0003:         * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
0004:         * All rights reserved.
0005:         *
0006:         * This program is free software; you can redistribute it and/or modify
0007:         * it under the terms of the GNU General Public License as published by
0008:         * the Free Software Foundation; either version 2 of the License, or
0009:         * (at your option) any later version.
0010:         *
0011:         * This program is distributed in the hope that it will be useful,
0012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014:         * GNU General Public License for more details.
0015:         *
0016:         * You should have received a copy of the GNU General Public License
0017:         * along with this program; if not, write to the Free Software
0018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0019:         * 
0020:         * $Id: JDBCPersistentMap.java,v 1.5 2007/03/27 21:59:44 mlipp Exp $
0021:         *
0022:         * $Log: JDBCPersistentMap.java,v $
0023:         * Revision 1.5  2007/03/27 21:59:44  mlipp
0024:         * Fixed lots of checkstyle warnings.
0025:         *
0026:         * Revision 1.4  2006/09/29 12:32:13  drmlipp
0027:         * Consistently using WfMOpen as projct name now.
0028:         *
0029:         * Revision 1.3  2005/04/22 15:10:49  drmlipp
0030:         * Merged changes from 1.3 branch up to 1.3p15.
0031:         *
0032:         * Revision 1.1.1.3.6.5  2005/04/14 11:45:07  drmlipp
0033:         * More (minor) optimizations.
0034:         *
0035:         * Revision 1.1.1.3.6.4  2005/04/13 16:14:06  drmlipp
0036:         * Optimized db access.
0037:         *
0038:         * Revision 1.1.1.3.6.3  2005/04/11 14:33:11  drmlipp
0039:         * Improved message.
0040:         *
0041:         * Revision 1.2  2005/04/08 11:28:03  drmlipp
0042:         * Merged changes from 1.3 branch up to 1.3p6.
0043:         *
0044:         * Revision 1.1.1.3.6.2  2005/03/18 21:59:00  drmlipp
0045:         * Fixed db access optimization.
0046:         *
0047:         * Revision 1.1.1.3.6.1  2005/03/18 15:02:00  drmlipp
0048:         * Optimized (reduced number of DB accesses).
0049:         *
0050:         * Revision 1.1.1.3  2004/08/18 15:17:35  drmlipp
0051:         * Update to 1.2
0052:         *
0053:         * Revision 1.37  2004/02/09 14:57:49  lipp
0054:         * Added support for map id of type Long.
0055:         *
0056:         * Revision 1.36  2003/11/27 16:26:09  lipp
0057:         * Added specific exception type to allow reconstruction of SQLException
0058:         * when using JDBCPersistence.
0059:         *
0060:         * Revision 1.35  2003/11/03 12:41:23  lipp
0061:         * Added null vs. "" support for Oracle.
0062:         *
0063:         * Revision 1.34  2003/06/27 08:51:46  lipp
0064:         * Fixed copyright/license information.
0065:         *
0066:         * Revision 1.33  2003/05/23 12:11:13  lipp
0067:         * Fixed driver/db characteristics caching.
0068:         *
0069:         * Revision 1.32  2003/04/11 13:21:04  lipp
0070:         * Fixed NullPointerException
0071:         *
0072:         * Revision 1.31  2003/03/28 10:09:20  lipp
0073:         * Intriduced logging using commons-logging.
0074:         *
0075:         * Revision 1.30  2003/03/06 15:23:03  lipp
0076:         * Some special handling for oracle.
0077:         *
0078:         * Revision 1.29  2003/03/06 13:47:45  schlue
0079:         * Handling of null values fixed.
0080:         *
0081:         * Revision 1.28  2003/03/05 13:18:32  schlue
0082:         * Fixed column names for map and item removed (now dynamic).
0083:         *
0084:         * Revision 1.27  2003/03/05 09:42:39  lipp
0085:         * Temporary fix for UniversalPrepStmt.
0086:         *
0087:         * Revision 1.26  2003/02/21 16:38:51  lipp
0088:         * Introduced UniversalPrepStmt.
0089:         *
0090:         * Revision 1.25  2003/02/19 12:23:14  lipp
0091:         * Adapted parameter sequence for setBinary to usual style.
0092:         *
0093:         * Revision 1.24  2003/02/18 15:20:38  schlue
0094:         * svalue handling fixed.
0095:         *
0096:         * Revision 1.23  2003/02/05 15:34:22  lipp
0097:         * Removed unnecessary exception.
0098:         *
0099:         * Revision 1.22  2002/11/19 15:20:31  lipp
0100:         * Removed not needed semicolon.
0101:         *
0102:         * Revision 1.21  2002/10/08 11:57:03  schlue
0103:         * Code fixed for changing a connection with non-saved modifications.
0104:         * Problems with serialization fixed.
0105:         * Formal corrections acc. to style checker.
0106:         *
0107:         * Revision 1.20  2002/08/30 07:24:25  schlue
0108:         * isModified added.
0109:         *
0110:         * Revision 1.19  2002/08/26 20:23:13  lipp
0111:         * Lots of method renames.
0112:         *
0113:         * Revision 1.18  2002/08/26 14:17:07  lipp
0114:         * JavaDoc fixes.
0115:         *
0116:         * Revision 1.17  2002/08/26 09:43:31  schlue
0117:         * Code optimizations.
0118:         *
0119:         * Revision 1.16  2002/08/23 13:17:09  schlue
0120:         * Modifications and fixes acc. to code review.
0121:         *
0122:         * Revision 1.15  2002/08/22 17:17:26  schlue
0123:         * Testing of threshold for svalue against DB schema implemented.
0124:         * New utility operation for determining column length added.
0125:         * Optional oracle test environment.
0126:         *
0127:         * Revision 1.14  2002/08/22 10:58:53  schlue
0128:         * Utility method to determine column length added.
0129:         *
0130:         * Revision 1.13  2002/08/22 08:36:07  schlue
0131:         * Max key length added.
0132:         * Garbage collection optimzed.
0133:         *
0134:         * Revision 1.12  2002/08/20 09:34:34  lipp
0135:         * Removed static.
0136:         *
0137:         * Revision 1.11  2002/08/20 08:47:49  schlue
0138:         * Default value for maximum key length added.
0139:         * Advanced error/warning logging.
0140:         *
0141:         * Revision 1.10  2002/08/19 19:23:40  lipp
0142:         * Various minor improvements.
0143:         *
0144:         * Revision 1.9  2002/08/19 15:15:04  lipp
0145:         * Added logger.
0146:         *
0147:         * Revision 1.8  2002/08/19 13:38:50  schlue
0148:         * Determination of maximum key length added.
0149:         * clear() operation optimized.
0150:         *
0151:         * Revision 1.7  2002/08/17 19:00:57  lipp
0152:         * Made map id changeable.
0153:         *
0154:         * Revision 1.6  2002/08/15 16:57:20  schlue
0155:         * Performance optimization: Optional usage of statement batches.
0156:         *
0157:         * Revision 1.5  2002/04/03 12:53:04  lipp
0158:         * JavaDoc fixes.
0159:         *
0160:         * Revision 1.4  2001/12/10 09:15:17  schlue
0161:         * javadoc warnings corrected
0162:         *
0163:         * Revision 1.3  2001/12/07 14:39:54  schlue
0164:         * Modifications acc. to review
0165:         *
0166:         * Revision 1.2  2001/12/07 12:33:17  schlue
0167:         * Implementation of persistent map finished
0168:         *
0169:         * Revision 1.1  2001/12/04 15:37:51  lipp
0170:         * New package for persistent maps.
0171:         *
0172:         */
0173:
0174:        package de.danet.an.util.persistentmaps;
0175:
0176:        import java.io.IOException;
0177:        import java.io.Serializable;
0178:
0179:        import java.util.HashMap;
0180:        import java.util.HashSet;
0181:        import java.util.Iterator;
0182:        import java.util.Map;
0183:        import java.util.Set;
0184:        import java.util.StringTokenizer;
0185:
0186:        import java.sql.Connection;
0187:        import java.sql.PreparedStatement;
0188:        import java.sql.ResultSet;
0189:        import java.sql.SQLException;
0190:
0191:        import javax.sql.DataSource;
0192:
0193:        import de.danet.an.util.JDBCUtil;
0194:        import de.danet.an.util.PersistentMap;
0195:        import de.danet.an.util.UniversalPrepStmt;
0196:
0197:        /**
0198:         * This class provides an implementation of
0199:         * {@link de.danet.an.util.PersistentMap <code>PersistentMap</code>} that
0200:         * uses JDBC to implement the persistence.<P>
0201:         *
0202:         * The class uses an abstract SQL table model. The table consists of
0203:         * a column for the map id, the entry key and two value
0204:         * entries.<P>
0205:         *
0206:         * All columns except the second value entry are of type string, 
0207:         * with lengths as appropriate for the
0208:         * application. The second value field is of type BLOB (binary large
0209:         * object) and is used if either the value to be stored is not
0210:         * of type {@link java.lang.String <code>String</code>} or longer
0211:         * than a given limit.
0212:         * 
0213:         * The map id enables storing of several
0214:         * jdbc persistent maps in a single table. It is passed as paramter
0215:         * to all constructors of this class. Only a single instance for a
0216:         * map id may be created as creating two instances may
0217:         * corrupt caching.<P>
0218:         *
0219:         * The SQL statements used to retrieve and save data are configurable.
0220:         * Thus any table or view may be used as a base for a jdbc persistent map.<P>
0221:         *
0222:         * <b>Note that this implementation is not synchronized.</b> If multiple 
0223:         * threads access this map concurrently, and at least one of the threads 
0224:         * modifies the map structurally, it must be synchronized externally. 
0225:         * (A structural modification is any operation that adds or deletes one or more
0226:         * mappings; merely changing the value associated with a key that an instance 
0227:         * already contains is not a structural modification.) This is typically 
0228:         * accomplished by synchronizing on some object that naturally encapsulates the
0229:         * map. 
0230:         * This can be done at creation time, to prevent accidental unsynchronized 
0231:         * access to the map:
0232:         * <code>JDBCPersistentMap pm = new JDBCPersistentMap(...);</code>
0233:         * <code>Map m = Collections.synchronizedMap(pm);</code>
0234:         * Since only the methods defined by Map are synchronized by this 
0235:         * mechanism, all supplemented methods (like 'load' or 'store' have to be
0236:         * synchronized on the map object 'm', created above, e.g.:
0237:         * <code>synchronized(m) {</code>
0238:         * <code>    pm.load(); // Must be in the synchronized block</code>
0239:         * <code>}</code><P>
0240:         *
0241:         * The class is serializable. Note, however, that the database connection
0242:         * is transient.
0243:         */
0244:        public class JDBCPersistentMap extends HashMap implements 
0245:                PersistentMap, Serializable {
0246:            private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
0247:                    .getLog(JDBCPersistentMap.class);
0248:
0249:            /**
0250:             * The map id used by this map.
0251:             */
0252:            private Object id = null;
0253:
0254:            /**
0255:             * The database table name used for this map.
0256:             */
0257:            private String dbTableName = null;
0258:
0259:            /**
0260:             * The column name of the "map" key attribute.
0261:             * Modifications are triggered by changes to the update statement.
0262:             */
0263:            private String mapColumnName = "MAPID";
0264:
0265:            /**
0266:             * The column name of the "item" key attribute.
0267:             * Modifications are triggered by changes to the update statement.
0268:             */
0269:            private String itemColumnName = "ITEM";
0270:
0271:            /**
0272:             * The SQL statement used to retrieve data.
0273:             */
0274:            private String loadStatement = null;
0275:
0276:            /**
0277:             * The SQL statement used to insert data.
0278:             */
0279:            private String insertStatement = null;
0280:
0281:            /**
0282:             * The SQL statement used to update data.
0283:             */
0284:            private String updateStatement = null;
0285:
0286:            /**
0287:             * The SQL statement used to delete data.
0288:             */
0289:            private String deleteStatement = null;
0290:
0291:            /**
0292:             * The SQL statement used to delete all data of a map.
0293:             */
0294:            private String deleteAllStatement = null;
0295:
0296:            /**
0297:             * The maximum length of the string value in the database.
0298:             */
0299:            private int sValueMax = 256;
0300:
0301:            /**
0302:             * The associated data source.
0303:             */
0304:            private transient DataSource dataSource = null;
0305:
0306:            /**
0307:             * The database URL of the current configuration.
0308:             */
0309:            private transient String configDbUrl = null;
0310:
0311:            /**
0312:             * Indicated that the dataSource has changed;
0313:             */
0314:            private transient boolean dataSourceChanged = true;
0315:
0316:            /**
0317:             * The database connection used for store and load.
0318:             */
0319:            private transient Connection dbConnection = null;
0320:
0321:            /**
0322:             * The databse properties.
0323:             */
0324:            private transient JDBCUtil.DBProperties dbProps = null;
0325:
0326:            /** Indicates that map id has never been used before. */
0327:            private boolean isNewMap = false;
0328:
0329:            /**
0330:             * Flag, indicating if the current map has already been loaded.
0331:             */
0332:            private boolean hasBeenLoaded = false;
0333:
0334:            /**
0335:             * Flag, indicating if the current map has been cleared.
0336:             */
0337:            private boolean hasBeenCleared = false;
0338:
0339:            /**
0340:             * Flag, indicating if there are any non-saved modifications.
0341:             */
0342:            private boolean isModified = false;
0343:
0344:            /**
0345:             * List of inserted keys to map entries.
0346:             */
0347:            private Set insertList = new HashSet();
0348:
0349:            /**
0350:             * List of updated keys to map entries.
0351:             */
0352:            private Set updateList = new HashSet();
0353:
0354:            /**
0355:             * List of deleted map entries.
0356:             */
0357:            private Set deleteList = new HashSet();
0358:
0359:            /**
0360:             * Prepared statement for loading map entries.
0361:             */
0362:            private transient PreparedStatement loadPStmt = null;
0363:
0364:            /**
0365:             * Prepared statement for inserting map entries.
0366:             */
0367:            private transient UniversalPrepStmt insertPStmt = null;
0368:
0369:            /**
0370:             * Prepared statement for updating map entries.
0371:             */
0372:            private transient UniversalPrepStmt updatePStmt = null;
0373:
0374:            /**
0375:             * Prepared statement for deleting map entries.
0376:             */
0377:            private transient PreparedStatement deletePStmt = null;
0378:
0379:            /**
0380:             * Prepared statement for deleting all map entries.
0381:             */
0382:            private transient PreparedStatement deleteAllPStmt = null;
0383:
0384:            /**
0385:             * Class for storing string/binary element of a map value.
0386:             */
0387:            private class MapValue {
0388:                String svalue = null;
0389:                Object bvalue = null;
0390:            }
0391:
0392:            /**
0393:             * Returns a new JDBC persistent map. The map is formed by all entries
0394:             * in the underlying table with the given map id. The
0395:             * table used by the default SQL statements is 
0396:             * <code>DEFAULTPERSISTENCEMAP</code>.
0397:             *
0398:             * @param dataSource the data source that will be used to obtain
0399:             * connections.
0400:             * @param mapId the map id.
0401:             * @throws SQLException if a database related error occurs
0402:             */
0403:            public JDBCPersistentMap(DataSource dataSource, String mapId)
0404:                    throws SQLException {
0405:                this (dataSource, mapId, "DEFAULTPERSISTENCEMAP");
0406:            }
0407:
0408:            /**
0409:             * Returns a new JDBC persistent map. The map is formed by all entries
0410:             * in the underlying table with the given map id. The
0411:             * table used by the default SQL statements is 
0412:             * <code>DEFAULTPERSISTENCEMAP</code>.
0413:             *
0414:             * @param dataSource the data source that will be used to obtain
0415:             * connections.
0416:             * @param mapId the map id.
0417:             * @throws SQLException if a database related error occurs
0418:             */
0419:            public JDBCPersistentMap(DataSource dataSource, Long mapId)
0420:                    throws SQLException {
0421:                this (dataSource, mapId, "DEFAULTPERSISTENCEMAP");
0422:            }
0423:
0424:            /**
0425:             * Returns a new JDBC persistent map. The map is formed by all entries
0426:             * in the underlying table with the given persistence group.
0427:             *
0428:             * @param dataSource the data source that will be used to obtain
0429:             * connections.
0430:             * @param mapId the map id.
0431:             * @param dbtable the table used in the default SQL statements.
0432:             * @throws SQLException if a database related error occurs
0433:             */
0434:            public JDBCPersistentMap(DataSource dataSource, String mapId,
0435:                    String dbtable) throws SQLException {
0436:                init(dataSource, mapId, dbtable);
0437:            }
0438:
0439:            /**
0440:             * Returns a new JDBC persistent map. The map is formed by all entries
0441:             * in the underlying table with the given persistence group.
0442:             *
0443:             * @param dataSource the data source that will be used to obtain
0444:             * connections.
0445:             * @param mapId the map id.
0446:             * @param dbtable the table used in the default SQL statements.
0447:             * @throws SQLException if a database related error occurs
0448:             */
0449:            public JDBCPersistentMap(DataSource dataSource, Long mapId,
0450:                    String dbtable) throws SQLException {
0451:                init(dataSource, mapId, dbtable);
0452:            }
0453:
0454:            private void init(DataSource ds, Object mapId, String dbtable)
0455:                    throws SQLException {
0456:                setDataSource(ds);
0457:                id = mapId;
0458:                dbTableName = dbtable;
0459:                loadStatement = "SELECT ITEM, SVALUE, BVALUE FROM " + dbtable
0460:                        + " WHERE MAPID = ?";
0461:                insertStatement = "INSERT INTO " + dbtable
0462:                        + " (MAPID, ITEM, SVALUE, BVALUE) VALUES (?, ?, ?, ?)";
0463:                updateStatement = "UPDATE "
0464:                        + dbtable
0465:                        + " SET SVALUE = ?, BVALUE = ? WHERE MAPID = ? AND ITEM = ?";
0466:                deleteStatement = "DELETE FROM " + dbtable
0467:                        + " WHERE MAPID = ? AND ITEM = ?";
0468:                deleteAllStatement = "DELETE FROM " + dbtable
0469:                        + " WHERE MAPID = ?";
0470:            }
0471:
0472:            /**
0473:             * Set the data source for this map. This must be called after
0474:             * deserialization. Calling this method resets the connection and
0475:             * must therefore be followed by a call to {@link #setConnection
0476:             * <code>setConnection</code>}.
0477:             * @param dataSource the data source that will be used to obtain
0478:             * connections.
0479:             * @throws SQLException if a database related error occurs
0480:             */
0481:            public void setDataSource(DataSource dataSource)
0482:                    throws SQLException {
0483:                setConnection(null);
0484:                this .dataSource = dataSource;
0485:                dataSourceChanged = true;
0486:            }
0487:
0488:            /**
0489:             * Sets the map id for this map. Clears the cached modifications
0490:             * as a side effect if the map id differs from the current map id.
0491:             *
0492:             * @param mapId the new map id.
0493:             * @see #getMapId
0494:             */
0495:            public void setMapId(String mapId) {
0496:                if (mapId.equals(id)) {
0497:                    return;
0498:                }
0499:                clearModifications();
0500:                id = mapId;
0501:            }
0502:
0503:            /**
0504:             * Sets the map id for this map. Clears the cached modifications
0505:             * as a side effect if the map id differs from the current map id.
0506:             *
0507:             * @param mapId the new map id.
0508:             * @see #getMapId
0509:             */
0510:            public void setMapId(Long mapId) {
0511:                if (mapId.equals(id)) {
0512:                    return;
0513:                }
0514:                clearModifications();
0515:                id = mapId;
0516:            }
0517:
0518:            private void clearModifications() {
0519:                super .clear();
0520:                insertList.clear();
0521:                updateList.clear();
0522:                deleteList.clear();
0523:                hasBeenLoaded = false;
0524:                hasBeenCleared = false;
0525:                isModified = false;
0526:                isNewMap = false;
0527:            }
0528:
0529:            /**
0530:             * May be called after constructor or <code>setMapId</code> and
0531:             * before the first call to <code>store()</code> to indicate that
0532:             * the map is newly created. This allows the persistent map
0533:             * implementation to optimize the storage bahaviour.
0534:             */
0535:            public void setNewMap() {
0536:                isNewMap = true;
0537:            }
0538:
0539:            /**
0540:             * Returns the map id of this map.
0541:             * @return the map id.
0542:             * @see #setMapId
0543:             */
0544:            public Object getMapId() {
0545:                return id;
0546:            }
0547:
0548:            /**
0549:             * Sets the SQL statement used to retrieve all entries for this map
0550:             * from the database table. The default is
0551:             * <pre>SELECT ITEM, SVALUE, BVALUE FROM <i>table</i> WHERE MAPID = ?</pre>
0552:             * where <code><i>table</i></code> defaults to
0553:             * <code>DEFAULTPERSISTENCEMAP</code> and can be set by calling the
0554:             * {@link #JDBCPersistentMap(String,String) extended constructor}.
0555:             * <P><b>NOTE: The statement must declare semantically corresponding 
0556:             * columns for all the selection and restriction values described in 
0557:             * the example above!</b></P>
0558:             *
0559:             * @param statement the load statement.
0560:             * @see #getLoadStatement
0561:             */
0562:            public void setLoadStatement(String statement) {
0563:                loadStatement = statement;
0564:                try {
0565:                    loadPStmt = (UniversalPrepStmt) closePreparedStatement(loadPStmt);
0566:                } catch (SQLException e) {
0567:                    logger.warn("Problem while closing prepared statement: "
0568:                            + e.getMessage());
0569:                }
0570:            }
0571:
0572:            /**
0573:             * Returns the SQL statement used to retrieve all entries for this
0574:             * map from the database table.
0575:             *
0576:             * @return the SQL statement.
0577:             * @see #setLoadStatement
0578:             */
0579:            public String getLoadStatement() {
0580:                return loadStatement;
0581:            }
0582:
0583:            /**
0584:             * Sets the SQL statement used to insert an entry for this map
0585:             * in the database table. The default is
0586:             * <pre>INSERT INTO <i>table</i> (MAPID, ITEM, SVALUE, BVALUE) 
0587:             * VALUES (?, ?, ?, ?)</pre>
0588:             * where <code><i>table</i></code> defaults to
0589:             * <code>DEFAULTPERSISTENCEMAP</code> and can be set by calling the
0590:             * {@link #JDBCPersistentMap(String,String) extended constructor}.
0591:             * <P><b>NOTE: The statement must declare semantically corresponding 
0592:             * columns for all the values described in the example above!</b></P>
0593:             *
0594:             * @param statement the insert statement.
0595:             * @see #getInsertStatement
0596:             */
0597:            public void setInsertStatement(String statement) {
0598:                insertStatement = statement;
0599:                try {
0600:                    insertPStmt = (UniversalPrepStmt) closePreparedStatement(insertPStmt);
0601:                } catch (SQLException e) {
0602:                    logger.warn("Problem while closing prepared statement: "
0603:                            + e.getMessage());
0604:                }
0605:            }
0606:
0607:            /**
0608:             * Returns the SQL statement used to insert an entry for this
0609:             * map into the database table.
0610:             *
0611:             * @return the SQL statement.
0612:             * @see #setInsertStatement
0613:             */
0614:            public String getInsertStatement() {
0615:                return insertStatement;
0616:            }
0617:
0618:            /**
0619:             * Sets the SQL statement used to update an entry for this map in
0620:             * the database table. The default is <pre>UPDATE <i>table</i> SET
0621:             * SVALUE = ?, BVALUE = ? WHERE MAPID=? AND ITEM=?</pre> where
0622:             * <code><i>table</i></code> defaults to
0623:             * <code>DEFAULTPERSISTENCEMAP</code> and can be set by calling
0624:             * the {@link #JDBCPersistentMap(String,String) extended
0625:             * constructor}.  <P><b>NOTE: The statement must declare
0626:             * semantically corresponding columns for all the data and
0627:             * restriction values described in the example above! The names of
0628:             * the key columns in the restriction phrase have to be in the
0629:             * same order as above (first: map-ident, second: item-ident)</b></P>
0630:             *
0631:             * @param statement the update statement.
0632:             * @see #getUpdateStatement
0633:             */
0634:            public void setUpdateStatement(String statement) {
0635:                int startWhere = statement.toLowerCase().indexOf("where");
0636:                if (startWhere == -1) {
0637:                    throw new IllegalArgumentException(
0638:                            "No WHERE clause in statement.");
0639:                }
0640:                updateStatement = statement;
0641:                try {
0642:                    updatePStmt = (UniversalPrepStmt) closePreparedStatement(updatePStmt);
0643:                } catch (SQLException e) {
0644:                    logger.warn("Problem while closing prepared statement: "
0645:                            + e.getMessage());
0646:                }
0647:                // Determine key columns names
0648:                mapColumnName = null;
0649:                itemColumnName = null;
0650:                String whereClause = updateStatement.substring(startWhere);
0651:                StringTokenizer wtok = new StringTokenizer(whereClause);
0652:                int tokCnt = 0;
0653:                while (wtok.hasMoreTokens()) {
0654:                    String tok = wtok.nextToken();
0655:                    if (tokCnt == 1) {
0656:                        mapColumnName = tok;
0657:                    } else if (tokCnt == 5) {
0658:                        itemColumnName = tok;
0659:                    }
0660:                    tokCnt++;
0661:                }
0662:                if (mapColumnName == null) {
0663:                    throw new IllegalArgumentException(
0664:                            "Cannot find map name column in WHERE clause of \""
0665:                                    + statement + "\"");
0666:                }
0667:                if (itemColumnName == null) {
0668:                    throw new IllegalArgumentException(
0669:                            "Cannot find item name column in WHERE clause of \""
0670:                                    + statement + "\"");
0671:                }
0672:            }
0673:
0674:            /**
0675:             * Returns the SQL statement used to update an entry for this
0676:             * map in the database table.
0677:             *
0678:             * @return the SQL statement.
0679:             * @see #setUpdateStatement
0680:             */
0681:            public String getUpdateStatement() {
0682:                return updateStatement;
0683:            }
0684:
0685:            /**
0686:             * Sets the SQL statement used to delete an entry for this map
0687:             * in the database table. The default is
0688:             * <pre>DELETE FROM <i>table</i> WHERE MAPID=? AND ITEM=?</pre>
0689:             * where <code><i>table</i></code> defaults to
0690:             * <code>DEFAULTPERSISTENCEMAP</code> and can be set by calling the
0691:             * {@link #JDBCPersistentMap(String,String) extended constructor}.
0692:             * <P><b>NOTE: The statement must declare semantically corresponding 
0693:             * columns for all the restriction values described in the example 
0694:             * above!</b></P>
0695:             *
0696:             * @param statement the delete statement.
0697:             * @see #getDeleteStatement
0698:             */
0699:            public void setDeleteStatement(String statement) {
0700:                deleteStatement = statement;
0701:                deletePStmt = null;
0702:            }
0703:
0704:            /**
0705:             * Returns the SQL statement used to delete an entry for this
0706:             * map in the database table.
0707:             *
0708:             * @return the SQL statement.
0709:             * @see #setDeleteStatement
0710:             */
0711:            public String getDeleteStatement() {
0712:                return deleteStatement;
0713:            }
0714:
0715:            /**
0716:             * Sets the SQL statement used to delete all entries for this map
0717:             * in the database table. The default is
0718:             * <pre>DELETE FROM <i>table</i> WHERE MAPID=?</pre>
0719:             * where <code><i>table</i></code> defaults to
0720:             * <code>DEFAULTPERSISTENCEMAP</code> and can be set by calling the
0721:             * {@link #JDBCPersistentMap(String,String) extended constructor}.
0722:             * <P><b>NOTE: The statement must declare semantically corresponding 
0723:             * columns for all the restriction values described in the example 
0724:             * above!</b></P>
0725:             *
0726:             * @param statement the delete statement.
0727:             * @see #getDeleteAllStatement
0728:             */
0729:            public void setDeleteAllStatement(String statement) {
0730:                deleteAllStatement = statement;
0731:                deleteAllPStmt = null;
0732:            }
0733:
0734:            /**
0735:             * Returns the SQL statement used to delete all entries for this
0736:             * map in the database table.
0737:             *
0738:             * @return the SQL statement.
0739:             * @see #setDeleteAllStatement
0740:             */
0741:            public String getDeleteAllStatement() {
0742:                return deleteAllStatement;
0743:            }
0744:
0745:            /**
0746:             * Sets the maximum length for string value in the
0747:             * <code>SVALUE</code> column of the database table.  The default
0748:             * is <code>256</code>.  If the given length value is greater than
0749:             * the column length in the database scheme (a DB connection that
0750:             * supports column information assumed), the length value is restricted
0751:             * to the DB column length.
0752:             * @param limit the maximum length for values in the <code>SVALUE</code>
0753:             * column.
0754:             * @see #getSValueMax
0755:             */
0756:            public void setSValueMax(int limit) {
0757:                if (limit <= 0) {
0758:                    throw new IllegalArgumentException(
0759:                            "limit must be greater than zero");
0760:                }
0761:                if (dbConnection == null) {
0762:                    sValueMax = limit;
0763:                    return;
0764:                }
0765:                try {
0766:                    int sLength = JDBCUtil.getTableColumnSize(dbConnection,
0767:                            dbTableName, "SVALUE", limit);
0768:                    if (limit > sLength) {
0769:                        logger.warn("Illegal limit (" + limit
0770:                                + ") for maximum string value. "
0771:                                + "Using column length from database schema ("
0772:                                + sLength + ").");
0773:                        sValueMax = sLength;
0774:                    } else {
0775:                        sValueMax = limit;
0776:                    }
0777:                } catch (SQLException exc) {
0778:                    logger.error(exc.getMessage(), exc);
0779:                }
0780:            }
0781:
0782:            /**
0783:             * Returns the maximum length for string value in the <code>SVALUE</code>
0784:             * column of the database table.
0785:             *
0786:             * @return the current maximum length
0787:             * @see #setSValueMax
0788:             */
0789:            public int getSValueMax() {
0790:                return sValueMax;
0791:            }
0792:
0793:            /**
0794:             * Sets the database connection used in {@link #load <code>load</code>}
0795:             * and {@link #store <code>store</code>}.
0796:             * If connection is closed or changes, all prepared statements are 
0797:             * released.
0798:             * If a valid connection with a different database url (compared with
0799:             * the previous valid connection) is set, the svalue threshold is
0800:             * validated if it hasn't been checked before (@see #setSValueMax).
0801:             * @param con the Connection.
0802:             * @throws SQLException from the underlying JDBC calls
0803:             * @see #getConnection
0804:             */
0805:            public void setConnection(Connection con) throws SQLException {
0806:                boolean sameConnection = ((con == null) && (dbConnection == null))
0807:                        || ((con != null) && (dbConnection != null) && (dbConnection
0808:                                .equals(con)));
0809:                if ((con == null) || !sameConnection) {
0810:                    // Close all prepared statements
0811:                    loadPStmt = closePreparedStatement(loadPStmt);
0812:                    insertPStmt = (UniversalPrepStmt) closePreparedStatement(insertPStmt);
0813:                    updatePStmt = (UniversalPrepStmt) closePreparedStatement(updatePStmt);
0814:                    deletePStmt = closePreparedStatement(deletePStmt);
0815:                    deleteAllPStmt = closePreparedStatement(deleteAllPStmt);
0816:                }
0817:                if ((dataSource == null || dataSourceChanged) && con != null) {
0818:                    dbProps = JDBCUtil.dbProperties(dataSource, con);
0819:                    String newDbUrl = null;
0820:                    boolean sameDb = false;
0821:                    if (dataSource == null) {
0822:                        newDbUrl = con.getMetaData().getURL();
0823:                        sameDb = (configDbUrl != null && newDbUrl
0824:                                .equals(configDbUrl));
0825:                        configDbUrl = newDbUrl;
0826:                    }
0827:                    if (dataSourceChanged || !sameDb) {
0828:                        // get table column size for "string" column
0829:                        int sLength = JDBCUtil.getTableColumnSize(con,
0830:                                dbTableName, "SVALUE", sValueMax);
0831:                        if (sValueMax > sLength) {
0832:                            logger
0833:                                    .warn("Illegal limit for maximum string value. "
0834:                                            + "Using column length from database schema.");
0835:                            sValueMax = sLength;
0836:                        }
0837:                        // Simulate that all current values have just
0838:                        // been inserted, so that they will be stored with
0839:                        // the naxt call to "store"
0840:                        insertList.clear();
0841:                        updateList.clear();
0842:                        deleteList.clear();
0843:                        insertList.addAll(this .keySet());
0844:                        hasBeenLoaded = false;
0845:                    }
0846:                    dataSourceChanged = false;
0847:                }
0848:                dbConnection = con;
0849:            }
0850:
0851:            /**
0852:             * Returns the database connection set by 
0853:             * {@link #setConnection <code>setConnection</code>}.
0854:             *
0855:             * @return the current connection
0856:             * @see #setConnection
0857:             */
0858:            public Connection getConnection() {
0859:                return dbConnection;
0860:            }
0861:
0862:            /**
0863:             * Retrieves the information about the maximum string length of key 
0864:             * entries.
0865:             * @return the maximum string length of key entries
0866:             * @throws IOException problems while storing the map
0867:             */
0868:            public int maxKeyLength() throws IOException {
0869:                if (dbConnection == null) {
0870:                    throw new IllegalStateException("No connection set");
0871:                }
0872:                final int defaultMaxKeyLength = 50;
0873:                try {
0874:                    // Request keylength value from database schema
0875:                    int kLength = JDBCUtil.getTableColumnSize(dbConnection,
0876:                            dbTableName, mapColumnName, defaultMaxKeyLength);
0877:                    return kLength;
0878:                } catch (SQLException exc) {
0879:                    throw new PersistentMapSQLException(exc);
0880:                }
0881:            }
0882:
0883:            /**
0884:             * Loads the map from persistent store.
0885:             * The map is cleared before loading.
0886:             *
0887:             * @throws IOException problems while loading the map
0888:             */
0889:            public void load() throws IOException {
0890:                if (dbConnection == null) {
0891:                    throw new IllegalStateException("No connection set");
0892:                }
0893:                ResultSet result = null;
0894:                try {
0895:                    if (loadPStmt == null) {
0896:                        loadPStmt = new UniversalPrepStmt(dataSource,
0897:                                dbConnection, loadStatement);
0898:                    }
0899:                    setMapId(loadPStmt, 1);
0900:                    result = loadPStmt.executeQuery();
0901:                    // Remove current entries and then add loaded values
0902:                    super .clear();
0903:                    insertList.clear();
0904:                    updateList.clear();
0905:                    deleteList.clear();
0906:                    while (result.next()) {
0907:                        String key = result.getString(1);
0908:                        Object value = result.getString(2);
0909:                        if (value == null) {
0910:                            try {
0911:                                value = JDBCUtil.getBinary(result, 3);
0912:                            } catch (ClassNotFoundException exc) {
0913:                                throw new IOException(exc.getMessage());
0914:                            }
0915:                        }
0916:                        super .put(key, value);
0917:                    }
0918:                    result.close();
0919:                } catch (SQLException exc) {
0920:                    throw new PersistentMapSQLException(exc);
0921:                }
0922:                hasBeenLoaded = true;
0923:                isModified = false;
0924:            }
0925:
0926:            /**
0927:             * Stores the map in persistent store.
0928:             * If the set has not been loaded before, all entries with the current
0929:             * map id are deleted from the persistent store first.
0930:             * Only modified (new, changed, deleted) map entries are changed in the 
0931:             * peristent store.
0932:             *
0933:             * @throws IOException problems while storing the map
0934:             */
0935:            public void store() throws IOException {
0936:                if (dbConnection == null) {
0937:                    throw new IllegalStateException("No connection set");
0938:                }
0939:                if (!hasBeenLoaded || hasBeenCleared) {
0940:                    if (!isNewMap) {
0941:                        /* First delete all existing values for that id in the
0942:                         * persistent store */
0943:                        try {
0944:                            if (deleteAllPStmt == null) {
0945:                                deleteAllPStmt = new UniversalPrepStmt(
0946:                                        dataSource, dbConnection,
0947:                                        deleteAllStatement);
0948:                            }
0949:                            setMapId(deleteAllPStmt, 1);
0950:                            int hits = deleteAllPStmt.executeUpdate();
0951:                        } catch (SQLException exc) {
0952:                            throw new PersistentMapSQLException(exc);
0953:                        }
0954:                    }
0955:                    hasBeenLoaded = true;
0956:                    hasBeenCleared = false;
0957:                }
0958:                isNewMap = false;
0959:                // Iterate through all the modification tracking lists
0960:                doDelete();
0961:                doInsert();
0962:                doUpdate();
0963:                isModified = false;
0964:            }
0965:
0966:            /**
0967:             * Removes all mappings from this map.
0968:             * This implementation ensures consistency between the map and the 
0969:             * persistent store.
0970:             *
0971:             */
0972:            public void clear() {
0973:                super .clear();
0974:                insertList.clear();
0975:                updateList.clear();
0976:                deleteList.clear();
0977:                hasBeenCleared = true;
0978:                isModified = false;
0979:            }
0980:
0981:            /**
0982:             * Associates the specified value with the specified key in this map.
0983:             * The key has to have a non-null value.
0984:             * If the map previously contained a mapping for this key, the old value 
0985:             * is replaced.
0986:             * This implementation ensures consistency between the map and the 
0987:             * persistent store.
0988:             *
0989:             * @param key key with which the specified value is to be associated.
0990:             * @param value value to be associated with the specified key.
0991:             * @return previous value associated with specified key, or null if 
0992:             * there was no mapping for key. 
0993:             */
0994:            public Object put(Object key, Object value) {
0995:                if (key == null || !(key instanceof  String)) {
0996:                    throw new IllegalArgumentException(
0997:                            "Key must be non-null and of type String");
0998:                }
0999:                Object oldValue = null;
1000:                if (containsKey(key)) {
1001:                    // Existing entry
1002:                    oldValue = super .put(key, value);
1003:                    // Changing an inserted entry leaves it in state "inserted"
1004:                    if (!insertList.contains(key)
1005:                            && ((oldValue == null && value != null)
1006:                                    || (oldValue != null && value == null) || (oldValue != null && !oldValue
1007:                                    .equals(value)))) {
1008:                        updateList.add(key);
1009:                    }
1010:                } else {
1011:                    // New (or prior deleted) entry
1012:                    // Adding a prior deleted entry brings it to state "updated"
1013:                    super .put(key, value);
1014:                    // The modification lists maybe null during readObject of
1015:                    // a JDBCPersistantMap (for the restauration of the map entries)
1016:                    if (insertList != null) {
1017:                        if (deleteList.contains(key)) {
1018:                            deleteList.remove(key);
1019:                            updateList.add(key);
1020:                        } else {
1021:                            insertList.add(key);
1022:                        }
1023:                    }
1024:                }
1025:                isModified = true;
1026:                return oldValue;
1027:            }
1028:
1029:            /**
1030:             * Removes the mapping for this key from this map if present.
1031:             * This implementation ensures consistency between the map and the 
1032:             * persistent store.
1033:             *
1034:             * @param key key with which the specified value is to be associated.
1035:             * @return previous value associated with specified key, or null if 
1036:             * there was no mapping for key. 
1037:             */
1038:            public Object remove(Object key) {
1039:                if (key == null || !containsKey(key)) {
1040:                    return null;
1041:                }
1042:                // If it has been inserted just before, remove all traces
1043:                if (insertList.contains(key)) {
1044:                    insertList.remove(key);
1045:                } else {
1046:                    // otherwise mark as removed
1047:                    // It doesn't matter any more if entry has been updated before
1048:                    updateList.remove(key);
1049:                    deleteList.add(key);
1050:                }
1051:                isModified = true;
1052:                return super .remove(key);
1053:            }
1054:
1055:            /**
1056:             * Copies all of the mappings from the specified map to this map.
1057:             * These mappings will replace any mappings that this map had for any of 
1058:             * the keys currently in the specified map.
1059:             * This implementation ensures consistency between the map and the 
1060:             * persistent store.
1061:             *
1062:             * @param t Mappings to be stored in this map.
1063:             */
1064:            public void putAll(Map t) {
1065:                for (Iterator it = t.keySet().iterator(); it.hasNext();) {
1066:                    Object key = it.next();
1067:                    put(key, t.get(key));
1068:                }
1069:            }
1070:
1071:            /**
1072:             * Indicates whether modifications need to be saved currently.
1073:             * @return true, if there are non-saved modifications, otherwise false.
1074:             */
1075:            public boolean isModified() {
1076:                return isModified;
1077:            }
1078:
1079:            /**
1080:             * Performs an update of the entry with the given key in the persistent
1081:             * store.
1082:             *
1083:             * @param withBatch flag, indicating if statement batches should be used
1084:             * @throws IOException problems while updating the entry
1085:             * @throws IllegalStateException if no connection has been set
1086:             */
1087:            private void doUpdate() throws IOException {
1088:                try {
1089:                    if (updateList.size() == 0) {
1090:                        return;
1091:                    }
1092:                    if (updatePStmt == null) {
1093:                        updatePStmt = new UniversalPrepStmt(dataSource,
1094:                                dbConnection, updateStatement);
1095:                    }
1096:                    Iterator keys = updateList.iterator();
1097:                    while (keys.hasNext()) {
1098:                        final String key = (String) keys.next();
1099:                        final MapValue value = getValue(key);
1100:                        updatePStmt.setString(1, value.svalue);
1101:                        updatePStmt.setBinary(2, value.bvalue);
1102:                        setMapId(updatePStmt, 3);
1103:                        updatePStmt.setString(4, key);
1104:                        if (dbProps.supportsBatchUpdates()) {
1105:                            updatePStmt.addBatch();
1106:                        } else {
1107:                            int hits = updatePStmt.executeUpdate();
1108:                            if (hits != 1) {
1109:                                throw new IOException(
1110:                                        "Data store not consistent "
1111:                                                + "(hits on update = " + hits
1112:                                                + ")!");
1113:                            }
1114:                        }
1115:                    }
1116:                    if (dbProps.supportsBatchUpdates()) {
1117:                        int[] result = updatePStmt.executeBatch();
1118:                        if (result.length != updateList.size()) {
1119:                            throw new IOException(
1120:                                    "Incorrect number of commands "
1121:                                            + "while executing update batch.");
1122:                        } else {
1123:                            for (int i = 0; i < result.length; i++) {
1124:                                if ((result[i] != 1) && (result[i] != -2)) {
1125:                                    throw new IOException(
1126:                                            "Data store not consistent "
1127:                                                    + "(hits on update = "
1128:                                                    + result[i] + ")!");
1129:                                }
1130:                            }
1131:                        }
1132:                    }
1133:                } catch (SQLException exc) {
1134:                    throw new PersistentMapSQLException(exc);
1135:                }
1136:                updateList.clear();
1137:            }
1138:
1139:            /**
1140:             * Deletes entry of the current map with the given key in the 
1141:             * persistent store.
1142:             *
1143:             * @throws IOException problems while deleting the entry
1144:             * @throws IllegalStateException if no connection has been set
1145:             */
1146:            private void doDelete() throws IOException {
1147:                try {
1148:                    if (deleteList.size() == 0) {
1149:                        return;
1150:                    }
1151:                    if (deletePStmt == null) {
1152:                        deletePStmt = new UniversalPrepStmt(dataSource,
1153:                                dbConnection, deleteStatement);
1154:                    }
1155:                    Iterator keys = deleteList.iterator();
1156:                    while (keys.hasNext()) {
1157:                        final String key = (String) keys.next();
1158:                        setMapId(deletePStmt, 1);
1159:                        deletePStmt.setString(2, key);
1160:                        if (dbProps.supportsBatchUpdates()) {
1161:                            deletePStmt.addBatch();
1162:                        } else {
1163:                            int hits = deletePStmt.executeUpdate();
1164:                            if (hits != 1) {
1165:                                throw new IOException(
1166:                                        "Data store not consistent "
1167:                                                + "(hits on delete = " + hits
1168:                                                + ")!");
1169:                            }
1170:                        }
1171:                    }
1172:                    if (dbProps.supportsBatchUpdates()) {
1173:                        int[] result = deletePStmt.executeBatch();
1174:                        if (result.length != deleteList.size()) {
1175:                            throw new IOException(
1176:                                    "Incorrect number of commands "
1177:                                            + "while executing delete batch.");
1178:                        } else {
1179:                            for (int i = 0; i < result.length; i++) {
1180:                                if ((result[i] != 1) && (result[i] != -2)) {
1181:                                    throw new IOException(
1182:                                            "Data store not consistent "
1183:                                                    + "(hits on delete = "
1184:                                                    + result[i] + ")!");
1185:                                }
1186:                            }
1187:                        }
1188:                    }
1189:                } catch (SQLException exc) {
1190:                    throw new PersistentMapSQLException(exc);
1191:                }
1192:                deleteList.clear();
1193:            }
1194:
1195:            /**
1196:             * Inserts entry of the current map with the given key in the 
1197:             * persistent store.
1198:             *
1199:             * @throws IOException problems while inserting the entry
1200:             * @throws IllegalStateException if no connection has been set
1201:             */
1202:            private void doInsert() throws IOException {
1203:                try {
1204:                    if (insertList.size() == 0) {
1205:                        return;
1206:                    }
1207:                    if (insertPStmt == null) {
1208:                        insertPStmt = new UniversalPrepStmt(dataSource,
1209:                                dbConnection, insertStatement, new String[] {
1210:                                        mapColumnName, itemColumnName });
1211:                    }
1212:                    Iterator keys = insertList.iterator();
1213:                    while (keys.hasNext()) {
1214:                        final String key = (String) keys.next();
1215:                        final MapValue value = getValue(key);
1216:                        setMapId(insertPStmt, 1);
1217:                        insertPStmt.setString(2, key);
1218:                        insertPStmt.setString(3, value.svalue);
1219:                        insertPStmt.setBinary(4, value.bvalue);
1220:                        if (dbProps.supportsBatchUpdates()) {
1221:                            insertPStmt.addBatch();
1222:                        } else {
1223:                            int hits = insertPStmt.executeUpdate();
1224:                            if (hits != 1) {
1225:                                throw new IOException(
1226:                                        "Data store not consistent "
1227:                                                + "(hits on insert = " + hits
1228:                                                + ")!");
1229:                            }
1230:                        }
1231:                    }
1232:                    if (dbProps.supportsBatchUpdates()) {
1233:                        int[] result = insertPStmt.executeBatch();
1234:                        if (result.length != insertList.size()) {
1235:                            throw new IOException(
1236:                                    "Incorrect number of commands "
1237:                                            + "while executing insert batch.");
1238:                        } else {
1239:                            for (int i = 0; i < result.length; i++) {
1240:                                if ((result[i] != 1) && (result[i] != -2)) {
1241:                                    throw new IOException(
1242:                                            "Data store not consistent "
1243:                                                    + "(hits on insert = "
1244:                                                    + result[i] + ")!");
1245:                                }
1246:                            }
1247:                        }
1248:                    }
1249:                } catch (SQLException exc) {
1250:                    throw new PersistentMapSQLException(exc);
1251:                }
1252:                insertList.clear();
1253:            }
1254:
1255:            /**
1256:             * Verify if the string will be stored as string, not as object.
1257:             * @param value the string
1258:             * @return <code>true</code> if the string will be stored as "svalue"
1259:             */
1260:            protected boolean isSValue(String value) {
1261:                return (value.length() <= sValueMax)
1262:                        && (!dbProps.isOracle() || ((String) value).length() > 0);
1263:            }
1264:
1265:            /**
1266:             * Returns a map value for a given key.
1267:             *
1268:             * @param key key to retrieve value for.
1269:             * @return value for given key. 
1270:             */
1271:            private MapValue getValue(String key) {
1272:                MapValue mapValue = new MapValue();
1273:                Object value = get(key);
1274:                if ((value instanceof  String) && isSValue((String) value)) {
1275:                    mapValue.svalue = (String) value;
1276:                } else {
1277:                    mapValue.bvalue = value;
1278:                }
1279:                return mapValue;
1280:            }
1281:
1282:            /**
1283:             * Sets the map id in a prepared statement.
1284:             * @param stmt the statement
1285:             * @param offset the offset
1286:             */
1287:            private void setMapId(PreparedStatement stmt, int offset)
1288:                    throws SQLException {
1289:                if (id instanceof  String) {
1290:                    stmt.setString(offset, (String) id);
1291:                } else {
1292:                    stmt.setLong(offset, ((Long) id).longValue());
1293:                }
1294:            }
1295:
1296:            /**
1297:             * Closes an existing prepared statement.
1298:             *
1299:             * @param pStmt the prepared statement to be closed
1300:             * @throws SQLException if no connection has been set
1301:             * @return always null. 
1302:             */
1303:            private PreparedStatement closePreparedStatement(
1304:                    PreparedStatement pStmt) throws SQLException {
1305:                if (pStmt != null) {
1306:                    pStmt.close();
1307:                }
1308:                return null;
1309:            }
1310:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.