Source Code Cross Referenced for EntityTable.java in  » EJB-Server-JBoss-4.2.1 » server » org » jboss » ejb » plugins » cmp » jdbc2 » schema » 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 » EJB Server JBoss 4.2.1 » server » org.jboss.ejb.plugins.cmp.jdbc2.schema 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * JBoss, Home of Professional Open Source.
0003:         * Copyright 2006, Red Hat Middleware LLC, and individual contributors
0004:         * as indicated by the @author tags. See the copyright.txt file in the
0005:         * distribution for a full listing of individual contributors.
0006:         *
0007:         * This is free software; you can redistribute it and/or modify it
0008:         * under the terms of the GNU Lesser General Public License as
0009:         * published by the Free Software Foundation; either version 2.1 of
0010:         * the License, or (at your option) any later version.
0011:         *
0012:         * This software is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015:         * Lesser General Public License for more details.
0016:         *
0017:         * You should have received a copy of the GNU Lesser General Public
0018:         * License along with this software; if not, write to the Free
0019:         * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020:         * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
0021:         */
0022:        package org.jboss.ejb.plugins.cmp.jdbc2.schema;
0023:
0024:        import org.jboss.deployment.DeploymentException;
0025:        import org.jboss.ejb.plugins.cmp.jdbc.SQLUtil;
0026:        import org.jboss.ejb.plugins.cmp.jdbc.JDBCUtil;
0027:        import org.jboss.ejb.plugins.cmp.jdbc.JDBCEntityPersistenceStore;
0028:        import org.jboss.ejb.plugins.cmp.jdbc.JDBCTypeFactory;
0029:        import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractCMRFieldBridge;
0030:        import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData;
0031:        import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCFunctionMappingMetaData;
0032:        import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCTypeMappingMetaData;
0033:        import org.jboss.ejb.plugins.cmp.jdbc2.bridge.JDBCEntityBridge2;
0034:        import org.jboss.ejb.plugins.cmp.jdbc2.bridge.JDBCCMPFieldBridge2;
0035:        import org.jboss.logging.Logger;
0036:        import org.jboss.mx.util.MBeanServerLocator;
0037:        import org.jboss.mx.util.MBeanProxyExt;
0038:        import org.jboss.system.ServiceControllerMBean;
0039:        import org.jboss.system.Registry;
0040:        import org.jboss.metadata.ConfigurationMetaData;
0041:        import org.jboss.metadata.MetaData;
0042:        import org.jboss.metadata.EntityMetaData;
0043:        import org.jboss.cache.invalidation.InvalidationManagerMBean;
0044:        import org.jboss.cache.invalidation.InvalidationGroup;
0045:        import org.w3c.dom.Element;
0046:
0047:        import javax.naming.InitialContext;
0048:        import javax.naming.NamingException;
0049:        import javax.sql.DataSource;
0050:        import javax.ejb.DuplicateKeyException;
0051:        import javax.ejb.EJBException;
0052:        import javax.ejb.NoSuchEntityException;
0053:        import javax.ejb.NoSuchObjectLocalException;
0054:        import javax.transaction.Transaction;
0055:        import javax.management.MBeanServer;
0056:        import javax.management.ObjectName;
0057:        import java.sql.Connection;
0058:        import java.sql.PreparedStatement;
0059:        import java.sql.SQLException;
0060:        import java.sql.ResultSet;
0061:        import java.util.Map;
0062:        import java.util.HashMap;
0063:        import java.util.ArrayList;
0064:        import java.util.List;
0065:
0066:        /**
0067:         * todo refactor optimistic locking
0068:         *
0069:         * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
0070:         * @version <tt>$Revision: 61754 $</tt>
0071:         */
0072:        public class EntityTable implements  Table {
0073:            private static final byte UNREFERENCED = 0;
0074:            private static final byte CLEAN = 1;
0075:            private static final byte DIRTY = 2;
0076:            private static final byte CREATED = 4;
0077:            private static final byte DELETED = 8;
0078:            private static final byte DIRTY_RELATIONS = 16;
0079:
0080:            private static final Object NOT_LOADED = new Object();
0081:
0082:            private JDBCEntityBridge2 entity;
0083:            private String tableName;
0084:            private int fieldsTotal;
0085:            private int relationsTotal;
0086:            private DataSource dataSource;
0087:            private Schema schema;
0088:            private int tableId;
0089:            private boolean dontFlushCreated;
0090:
0091:            private String deleteSql;
0092:            private String updateSql;
0093:            private String insertSql;
0094:            private String selectSql;
0095:            private String duplicatePkSql;
0096:
0097:            private final CommitStrategy insertStrategy;
0098:            private final CommitStrategy deleteStrategy;
0099:            private final CommitStrategy updateStrategy;
0100:
0101:            private Logger log;
0102:
0103:            private Cache cache;
0104:            private ServiceControllerMBean serviceController;
0105:            private ObjectName cacheName;
0106:
0107:            private int[] references;
0108:            private int[] referencedBy;
0109:
0110:            private ForeignKeyConstraint[] fkConstraints;
0111:
0112:            private CacheInvalidator cacheInvalidator;
0113:
0114:            public EntityTable(JDBCEntityMetaData metadata,
0115:                    JDBCEntityBridge2 entity, Schema schema, int tableId)
0116:                    throws DeploymentException {
0117:                try {
0118:                    InitialContext ic = new InitialContext();
0119:                    dataSource = (DataSource) ic.lookup(metadata
0120:                            .getDataSourceName());
0121:                } catch (NamingException e) {
0122:                    throw new DeploymentException("Filed to lookup: "
0123:                            + metadata.getDataSourceName(), e);
0124:                }
0125:
0126:                this .entity = entity;
0127:                tableName = SQLUtil.fixTableName(
0128:                        metadata.getDefaultTableName(), dataSource);
0129:                log = Logger.getLogger(getClass().getName() + "." + tableName);
0130:
0131:                this .schema = schema;
0132:                this .tableId = tableId;
0133:
0134:                final EntityMetaData entityMetaData = ((EntityMetaData) entity
0135:                        .getContainer().getBeanMetaData());
0136:                final ConfigurationMetaData containerConf = entityMetaData
0137:                        .getContainerConfiguration();
0138:                dontFlushCreated = containerConf.isInsertAfterEjbPostCreate();
0139:
0140:                // create cache
0141:                final Element cacheConf = containerConf.getContainerCacheConf();
0142:                final Element cachePolicy = cacheConf == null ? null : MetaData
0143:                        .getOptionalChild(cacheConf, "cache-policy-conf");
0144:
0145:                int minCapacity;
0146:                int maxCapacity;
0147:                if (cachePolicy != null) {
0148:                    String str = MetaData.getOptionalChildContent(cachePolicy,
0149:                            "min-capacity");
0150:                    minCapacity = (str == null ? 1000 : Integer.parseInt(str));
0151:                    str = MetaData.getOptionalChildContent(cachePolicy,
0152:                            "max-capacity");
0153:                    maxCapacity = (str == null ? 10000 : Integer.parseInt(str));
0154:                } else {
0155:                    minCapacity = 1000;
0156:                    maxCapacity = 10000;
0157:                }
0158:
0159:                final Element otherConf = cacheConf == null ? null : MetaData
0160:                        .getOptionalChild(cacheConf, "cache-policy-conf-other");
0161:
0162:                int partitionsTotal;
0163:                final boolean invalidable;
0164:                final Element batchCommitStrategy;
0165:                if (otherConf != null) {
0166:                    String str = MetaData.getOptionalChildContent(otherConf,
0167:                            "partitions");
0168:                    partitionsTotal = (str == null ? 10 : Integer.parseInt(str));
0169:                    batchCommitStrategy = MetaData.getOptionalChild(otherConf,
0170:                            "batch-commit-strategy");
0171:                    invalidable = MetaData.getOptionalChild(otherConf,
0172:                            "invalidable") == null ? false : true;
0173:                } else {
0174:                    partitionsTotal = 10;
0175:                    batchCommitStrategy = null;
0176:                    invalidable = false;
0177:                }
0178:
0179:                if (cachePolicy != null) {
0180:                    cache = new PartitionedTableCache(minCapacity, maxCapacity,
0181:                            partitionsTotal);
0182:
0183:                    String periodStr = MetaData.getOptionalChildContent(
0184:                            cachePolicy, "overager-period");
0185:                    String maxAgeStr = MetaData.getOptionalChildContent(
0186:                            cachePolicy, "max-bean-age");
0187:                    if (periodStr != null && maxAgeStr == null
0188:                            || maxAgeStr != null && periodStr == null) {
0189:                        throw new DeploymentException(
0190:                                "Failed to initialize age-out thread for entity "
0191:                                        + entity.getEntityName()
0192:                                        + ": overager-period or max-bean-age is missing!");
0193:                    } else if (periodStr != null && maxAgeStr != null) {
0194:                        long period = Long.parseLong(periodStr);
0195:                        long maxAge = Long.parseLong(maxAgeStr);
0196:                        ((PartitionedTableCache) cache).initOverager(period,
0197:                                maxAge, entity.getEntityName() + " overager");
0198:
0199:                        if (log.isTraceEnabled()) {
0200:                            log.trace("initialized age-out thread for "
0201:                                    + entity.getEntityName()
0202:                                    + ": overager-period=" + period
0203:                                    + ", max-bean-age=" + maxAge);
0204:                        }
0205:                    }
0206:
0207:                    final MBeanServer server = MBeanServerLocator.locateJBoss();
0208:                    serviceController = (ServiceControllerMBean) MBeanProxyExt
0209:                            .create(ServiceControllerMBean.class,
0210:                                    ServiceControllerMBean.OBJECT_NAME, server);
0211:                    try {
0212:                        cacheName = new ObjectName(
0213:                                "jboss.cmp:service=tablecache,ejbname="
0214:                                        + metadata.getName() + ",table="
0215:                                        + tableName);
0216:                        server.registerMBean(cache, cacheName);
0217:                        serviceController.create(cacheName);
0218:                    } catch (Exception e) {
0219:                        throw new DeploymentException(
0220:                                "Failed to register table cache for "
0221:                                        + tableName, e);
0222:                    }
0223:                } else {
0224:                    cache = Cache.NONE;
0225:                }
0226:
0227:                if (invalidable) {
0228:                    String groupName = entityMetaData
0229:                            .getDistributedCacheInvalidationConfig()
0230:                            .getInvalidationGroupName();
0231:                    String imName = entityMetaData
0232:                            .getDistributedCacheInvalidationConfig()
0233:                            .getInvalidationManagerName();
0234:
0235:                    InvalidationManagerMBean im = (InvalidationManagerMBean) Registry
0236:                            .lookup(imName);
0237:                    InvalidationGroup invalidationGroup = im
0238:                            .getInvalidationGroup(groupName);
0239:
0240:                    cacheInvalidator = new CacheInvalidator(cache, entity
0241:                            .getContainer().getTransactionManager(),
0242:                            invalidationGroup);
0243:                }
0244:
0245:                if (batchCommitStrategy == null) {
0246:                    insertStrategy = NON_BATCH_UPDATE;
0247:                    deleteStrategy = NON_BATCH_UPDATE;
0248:                    updateStrategy = NON_BATCH_UPDATE;
0249:                } else {
0250:                    log.debug("batch-commit-strategy enabled");
0251:                    insertStrategy = BATCH_UPDATE;
0252:                    deleteStrategy = BATCH_UPDATE;
0253:                    updateStrategy = BATCH_UPDATE;
0254:                }
0255:            }
0256:
0257:            public void start() throws DeploymentException {
0258:                final JDBCAbstractCMRFieldBridge[] cmrFields = entity
0259:                        .getCMRFields();
0260:                relationsTotal = (cmrFields != null ? cmrFields.length : 0);
0261:
0262:                JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity
0263:                        .getPrimaryKeyFields();
0264:                JDBCCMPFieldBridge2[] tableFields = (JDBCCMPFieldBridge2[]) entity
0265:                        .getTableFields();
0266:
0267:                // DELETE SQL
0268:                deleteSql = "delete from " + tableName + " where ";
0269:                deleteSql += pkFields[0].getColumnName() + "=?";
0270:                for (int i = 1; i < pkFields.length; ++i) {
0271:                    deleteSql += " and " + pkFields[i].getColumnName() + "=?";
0272:                }
0273:                log.debug("delete sql: " + deleteSql);
0274:
0275:                // INSERT SQL
0276:                insertSql = "insert into " + tableName + "(";
0277:                insertSql += tableFields[0].getColumnName();
0278:                for (int i = 1; i < tableFields.length; ++i) {
0279:                    insertSql += ", " + tableFields[i].getColumnName();
0280:                }
0281:                insertSql += ") values (?";
0282:                for (int i = 1; i < tableFields.length; ++i) {
0283:                    insertSql += ", ?";
0284:                }
0285:                insertSql += ")";
0286:                log.debug("insert sql: " + insertSql);
0287:
0288:                // UPDATE SQL
0289:                updateSql = "update " + tableName + " set ";
0290:                int setFields = 0;
0291:                for (int i = 0; i < tableFields.length; ++i) {
0292:                    JDBCCMPFieldBridge2 field = tableFields[i];
0293:                    if (!field.isPrimaryKeyMember()) {
0294:                        if (setFields++ > 0) {
0295:                            updateSql += ", ";
0296:                        }
0297:                        updateSql += field.getColumnName() + "=?";
0298:                    }
0299:                }
0300:                updateSql += " where ";
0301:                updateSql += pkFields[0].getColumnName() + "=?";
0302:                for (int i = 1; i < pkFields.length; ++i) {
0303:                    updateSql += " and " + pkFields[i].getColumnName() + "=?";
0304:                }
0305:
0306:                if (entity.getVersionField() != null) {
0307:                    updateSql += " and "
0308:                            + entity.getVersionField().getColumnName() + "=?";
0309:                }
0310:                log.debug("update sql: " + updateSql);
0311:
0312:                // SELECT SQL
0313:                String selectColumns = tableFields[0].getColumnName();
0314:                for (int i = 1; i < tableFields.length; ++i) {
0315:                    JDBCCMPFieldBridge2 field = tableFields[i];
0316:                    selectColumns += ", " + field.getColumnName();
0317:                }
0318:
0319:                String whereColumns = pkFields[0].getColumnName() + "=?";
0320:                for (int i = 1; i < pkFields.length; ++i) {
0321:                    whereColumns += " and " + pkFields[i].getColumnName()
0322:                            + "=?";
0323:                }
0324:
0325:                if (entity.getMetaData().hasRowLocking()) {
0326:                    JDBCEntityPersistenceStore manager = entity.getManager();
0327:                    JDBCTypeFactory typeFactory = manager.getJDBCTypeFactory();
0328:                    JDBCTypeMappingMetaData typeMapping = typeFactory
0329:                            .getTypeMapping();
0330:                    JDBCFunctionMappingMetaData rowLockingTemplate = typeMapping
0331:                            .getRowLockingTemplate();
0332:                    if (rowLockingTemplate == null) {
0333:                        throw new DeploymentException(
0334:                                "Row locking template is not defined for mapping: "
0335:                                        + typeMapping.getName());
0336:                    }
0337:
0338:                    selectSql = rowLockingTemplate.getFunctionSql(
0339:                            new Object[] { selectColumns, tableName,
0340:                                    whereColumns, null }, new StringBuffer())
0341:                            .toString();
0342:                } else {
0343:                    selectSql = "select ";
0344:                    selectSql += selectColumns;
0345:                    selectSql += " from " + tableName + " where ";
0346:                    selectSql += whereColumns;
0347:                }
0348:                log.debug("select sql: " + selectSql);
0349:
0350:                // DUPLICATE KEY
0351:                if (dontFlushCreated) {
0352:                    duplicatePkSql = "select ";
0353:                    duplicatePkSql += pkFields[0].getColumnName();
0354:                    for (int i = 1; i < pkFields.length; ++i) {
0355:                        duplicatePkSql += ", " + pkFields[i].getColumnName();
0356:                    }
0357:                    duplicatePkSql += " from " + tableName + " where ";
0358:                    duplicatePkSql += pkFields[0].getColumnName() + "=?";
0359:                    for (int i = 1; i < pkFields.length; ++i) {
0360:                        duplicatePkSql += " and " + pkFields[i].getColumnName()
0361:                                + "=?";
0362:                    }
0363:                    log.debug("duplicate pk sql: " + duplicatePkSql);
0364:                }
0365:
0366:                if (cacheName != null) {
0367:                    try {
0368:                        serviceController.start(cacheName);
0369:                    } catch (Exception e) {
0370:                        throw new DeploymentException(
0371:                                "Failed to start table cache.", e);
0372:                    }
0373:                }
0374:            }
0375:
0376:            public void stop() throws Exception {
0377:                if (cacheInvalidator != null) {
0378:                    cacheInvalidator.unregister();
0379:                }
0380:
0381:                if (cacheName != null) {
0382:                    serviceController.stop(cacheName);
0383:                    serviceController.destroy(cacheName);
0384:                    serviceController.remove(cacheName);
0385:                }
0386:                serviceController = null;
0387:            }
0388:
0389:            public StringBuffer appendColumnNames(JDBCCMPFieldBridge2[] fields,
0390:                    String alias, StringBuffer buf) {
0391:                for (int i = 0; i < fields.length; ++i) {
0392:                    if (i > 0) {
0393:                        buf.append(", ");
0394:                    }
0395:
0396:                    if (alias != null) {
0397:                        buf.append(alias).append(".");
0398:                    }
0399:
0400:                    buf.append(fields[i].getColumnName());
0401:                }
0402:
0403:                return buf;
0404:            }
0405:
0406:            public void addField() {
0407:                ++fieldsTotal;
0408:            }
0409:
0410:            public int addVersionField() {
0411:                return fieldsTotal++;
0412:            }
0413:
0414:            public ForeignKeyConstraint addFkConstraint(
0415:                    JDBCCMPFieldBridge2[] fkFields, EntityTable referenced) {
0416:                addReference(referenced);
0417:                referenced.addReferencedBy(this );
0418:
0419:                if (fkConstraints == null) {
0420:                    fkConstraints = new ForeignKeyConstraint[1];
0421:                } else {
0422:                    ForeignKeyConstraint[] tmp = fkConstraints;
0423:                    fkConstraints = new ForeignKeyConstraint[tmp.length + 1];
0424:                    System.arraycopy(tmp, 0, fkConstraints, 0, tmp.length);
0425:                }
0426:                final int fkindex = fkConstraints.length - 1;
0427:                final ForeignKeyConstraint fkc = new ForeignKeyConstraint(
0428:                        fkindex, fkFields);
0429:                fkConstraints[fkindex] = fkc;
0430:                return fkc;
0431:            }
0432:
0433:            public DataSource getDataSource() {
0434:                return dataSource;
0435:            }
0436:
0437:            public Object loadRow(ResultSet rs, boolean searchableOnly) {
0438:                View view = getView();
0439:                Object pk = view.loadPk(rs);
0440:                if (pk != null) {
0441:                    view.loadRow(rs, pk, searchableOnly);
0442:                } else if (log.isTraceEnabled()) {
0443:                    log.trace("loaded pk is null.");
0444:                }
0445:                return pk;
0446:            }
0447:
0448:            public Row getRow(Object id) {
0449:                return getView().getRow(id);
0450:            }
0451:
0452:            public boolean hasRow(Object id) {
0453:                return getView().hasRow(id);
0454:            }
0455:
0456:            public Row loadRow(Object id) throws SQLException {
0457:                View view = getView();
0458:
0459:                Row row = view.getRowByPk(id, false);
0460:                if (row != null) {
0461:                    if (log.isTraceEnabled()) {
0462:                        log.trace("row is already loaded: pk=" + id);
0463:                    }
0464:                    return row;
0465:                }
0466:
0467:                JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity
0468:                        .getPrimaryKeyFields();
0469:
0470:                Connection con = null;
0471:                PreparedStatement ps = null;
0472:                ResultSet rs = null;
0473:                try {
0474:                    if (log.isDebugEnabled()) {
0475:                        log.debug("executing sql: " + selectSql);
0476:                    }
0477:
0478:                    con = dataSource.getConnection();
0479:                    ps = con.prepareStatement(selectSql);
0480:
0481:                    int paramInd = 1;
0482:                    for (int i = 0; i < pkFields.length; ++i) {
0483:                        JDBCCMPFieldBridge2 pkField = pkFields[i];
0484:                        Object pkValue = pkField.getPrimaryKeyValue(id);
0485:                        paramInd = pkField.setArgumentParameters(ps, paramInd,
0486:                                pkValue);
0487:                    }
0488:
0489:                    rs = ps.executeQuery();
0490:
0491:                    if (!rs.next()) {
0492:                        throw new NoSuchEntityException("Row not found: " + id);
0493:                    }
0494:
0495:                    return view.loadRow(rs, id, false);
0496:                } catch (SQLException e) {
0497:                    log.error("Failed to load row: table=" + tableName
0498:                            + ", pk=" + id);
0499:                    throw e;
0500:                } finally {
0501:                    JDBCUtil.safeClose(rs);
0502:                    JDBCUtil.safeClose(ps);
0503:                    JDBCUtil.safeClose(con);
0504:                }
0505:            }
0506:
0507:            // Table implementation
0508:
0509:            public int getTableId() {
0510:                return tableId;
0511:            }
0512:
0513:            public String getTableName() {
0514:                return tableName;
0515:            }
0516:
0517:            public Table.View createView(Transaction tx) {
0518:                return new View(tx);
0519:            }
0520:
0521:            // Private
0522:
0523:            private void addReference(EntityTable table) {
0524:                boolean wasRegistered = false;
0525:                if (references != null) {
0526:                    for (int i = 0; i < references.length; ++i) {
0527:                        if (references[i] == table.getTableId()) {
0528:                            wasRegistered = true;
0529:                            break;
0530:                        }
0531:                    }
0532:
0533:                    if (!wasRegistered) {
0534:                        int[] tmp = references;
0535:                        references = new int[references.length + 1];
0536:                        System.arraycopy(tmp, 0, references, 0, tmp.length);
0537:                        references[tmp.length] = table.getTableId();
0538:                    }
0539:                } else {
0540:                    references = new int[1];
0541:                    references[0] = table.getTableId();
0542:                }
0543:
0544:                if (!wasRegistered) {
0545:                    if (log.isTraceEnabled()) {
0546:                        log.trace("references " + table.getTableName());
0547:                    }
0548:                }
0549:            }
0550:
0551:            private void addReferencedBy(EntityTable table) {
0552:                boolean wasRegistered = false;
0553:                if (referencedBy != null) {
0554:                    for (int i = 0; i < referencedBy.length; ++i) {
0555:                        if (referencedBy[i] == table.getTableId()) {
0556:                            wasRegistered = true;
0557:                            break;
0558:                        }
0559:                    }
0560:
0561:                    if (!wasRegistered) {
0562:                        int[] tmp = referencedBy;
0563:                        referencedBy = new int[referencedBy.length + 1];
0564:                        System.arraycopy(tmp, 0, referencedBy, 0, tmp.length);
0565:                        referencedBy[tmp.length] = table.getTableId();
0566:                    }
0567:                } else {
0568:                    referencedBy = new int[1];
0569:                    referencedBy[0] = table.getTableId();
0570:                }
0571:
0572:                if (!wasRegistered) {
0573:                    if (log.isTraceEnabled()) {
0574:                        log.trace("referenced by " + table.getTableName());
0575:                    }
0576:                }
0577:            }
0578:
0579:            private void delete(View view) throws SQLException {
0580:                JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity
0581:                        .getPrimaryKeyFields();
0582:
0583:                Connection con = null;
0584:                PreparedStatement ps = null;
0585:                try {
0586:                    if (log.isDebugEnabled()) {
0587:                        log.debug("executing : " + deleteSql);
0588:                    }
0589:
0590:                    con = dataSource.getConnection();
0591:                    ps = con.prepareStatement(deleteSql);
0592:
0593:                    int batchCount = 0;
0594:                    while (view.deleted != null) {
0595:                        Row row = view.deleted;
0596:
0597:                        int paramInd = 1;
0598:                        for (int pkInd = 0; pkInd < pkFields.length; ++pkInd) {
0599:                            JDBCCMPFieldBridge2 pkField = pkFields[pkInd];
0600:                            Object fieldValue = row.fields[pkField
0601:                                    .getRowIndex()];
0602:                            paramInd = pkField.setArgumentParameters(ps,
0603:                                    paramInd, fieldValue);
0604:                        }
0605:
0606:                        deleteStrategy.executeUpdate(ps);
0607:
0608:                        ++batchCount;
0609:                        row.flushStatus();
0610:                    }
0611:
0612:                    deleteStrategy.executeBatch(ps);
0613:
0614:                    if (view.deleted != null) {
0615:                        throw new IllegalStateException(
0616:                                "There are still rows to delete!");
0617:                    }
0618:
0619:                    if (log.isTraceEnabled()) {
0620:                        log.trace("deleted rows: " + batchCount);
0621:                    }
0622:                } catch (SQLException e) {
0623:                    log.error("Failed to delete view: " + e.getMessage(), e);
0624:                    throw e;
0625:                } finally {
0626:                    JDBCUtil.safeClose(ps);
0627:                    JDBCUtil.safeClose(con);
0628:                }
0629:            }
0630:
0631:            private void update(View view) throws SQLException {
0632:                JDBCCMPFieldBridge2[] tableFields = (JDBCCMPFieldBridge2[]) entity
0633:                        .getTableFields();
0634:                JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity
0635:                        .getPrimaryKeyFields();
0636:
0637:                Connection con = null;
0638:                PreparedStatement ps = null;
0639:                try {
0640:                    if (log.isDebugEnabled()) {
0641:                        log.debug("executing : " + updateSql);
0642:                    }
0643:
0644:                    con = dataSource.getConnection();
0645:                    ps = con.prepareStatement(updateSql);
0646:
0647:                    int batchCount = 0;
0648:                    while (view.dirty != null) {
0649:                        Row row = view.dirty;
0650:
0651:                        int paramInd = 1;
0652:                        for (int fInd = 0; fInd < tableFields.length; ++fInd) {
0653:                            JDBCCMPFieldBridge2 field = tableFields[fInd];
0654:                            if (!field.isPrimaryKeyMember()) {
0655:                                Object fieldValue = row.fields[field
0656:                                        .getRowIndex()];
0657:                                paramInd = field.setArgumentParameters(ps,
0658:                                        paramInd, fieldValue);
0659:                            }
0660:                        }
0661:
0662:                        for (int fInd = 0; fInd < pkFields.length; ++fInd) {
0663:                            JDBCCMPFieldBridge2 pkField = pkFields[fInd];
0664:                            Object fieldValue = row.fields[pkField
0665:                                    .getRowIndex()];
0666:                            paramInd = pkField.setArgumentParameters(ps,
0667:                                    paramInd, fieldValue);
0668:                        }
0669:
0670:                        JDBCCMPFieldBridge2 versionField = entity
0671:                                .getVersionField();
0672:                        if (versionField != null) {
0673:                            int versionIndex = versionField.getVersionIndex();
0674:                            Object curVersion = row.fields[versionIndex];
0675:                            paramInd = versionField.setArgumentParameters(ps,
0676:                                    paramInd, curVersion);
0677:
0678:                            Object newVersion = row.fields[versionField
0679:                                    .getRowIndex()];
0680:                            row.fields[versionIndex] = newVersion;
0681:                        }
0682:
0683:                        updateStrategy.executeUpdate(ps);
0684:
0685:                        ++batchCount;
0686:                        row.flushStatus();
0687:                    }
0688:
0689:                    updateStrategy.executeBatch(ps);
0690:
0691:                    if (log.isTraceEnabled()) {
0692:                        log.trace("updated rows: " + batchCount);
0693:                    }
0694:                } catch (SQLException e) {
0695:                    log.error("Failed to update: table=" + tableName, e);
0696:                    throw e;
0697:                } finally {
0698:                    JDBCUtil.safeClose(ps);
0699:                    JDBCUtil.safeClose(con);
0700:                }
0701:            }
0702:
0703:            private void insert(View view) throws SQLException {
0704:                JDBCCMPFieldBridge2[] tableFields = (JDBCCMPFieldBridge2[]) entity
0705:                        .getTableFields();
0706:                Connection con = null;
0707:                PreparedStatement ps = null;
0708:                try {
0709:                    if (log.isDebugEnabled()) {
0710:                        log.debug("executing : " + insertSql);
0711:                    }
0712:
0713:                    con = dataSource.getConnection();
0714:                    ps = con.prepareStatement(insertSql);
0715:
0716:                    int batchCount = 0;
0717:                    while (view.created != null) {
0718:                        Row row = view.created;
0719:
0720:                        int paramInd = 1;
0721:                        for (int fInd = 0; fInd < tableFields.length; ++fInd) {
0722:                            JDBCCMPFieldBridge2 field = tableFields[fInd];
0723:                            Object fieldValue = row.fields[field.getRowIndex()];
0724:                            paramInd = field.setArgumentParameters(ps,
0725:                                    paramInd, fieldValue);
0726:                        }
0727:
0728:                        insertStrategy.executeUpdate(ps);
0729:
0730:                        ++batchCount;
0731:                        row.flushStatus();
0732:                    }
0733:
0734:                    insertStrategy.executeBatch(ps);
0735:
0736:                    if (log.isTraceEnabled()) {
0737:                        log.trace("inserted rows: " + batchCount);
0738:                    }
0739:                } catch (SQLException e) {
0740:                    log
0741:                            .error("Failed to insert new rows: "
0742:                                    + e.getMessage(), e);
0743:                    throw e;
0744:                } finally {
0745:                    JDBCUtil.safeClose(ps);
0746:                    JDBCUtil.safeClose(con);
0747:                }
0748:            }
0749:
0750:            private EntityTable.View getView() {
0751:                return (EntityTable.View) schema.getView(this );
0752:            }
0753:
0754:            public class View implements  Table.View {
0755:                private final Transaction tx;
0756:
0757:                private Map rowByPk = new HashMap();
0758:                private Row created;
0759:                private Row deleted;
0760:                private Row dirty;
0761:                private Row dirtyRelations;
0762:                private Row clean;
0763:
0764:                private Row cacheUpdates;
0765:
0766:                private List rowsWithNullFks;
0767:
0768:                private boolean inFlush;
0769:
0770:                public View(Transaction tx) {
0771:                    this .tx = tx;
0772:                }
0773:
0774:                public Row getRow(Object pk) {
0775:                    Row row;
0776:                    if (pk == null) {
0777:                        row = new Row(this );
0778:                    } else {
0779:                        row = getRowByPk(pk, false);
0780:                        if (row == null) {
0781:                            row = createCleanRow(pk);
0782:                        }
0783:                    }
0784:                    return row;
0785:                }
0786:
0787:                public Row getRowByPk(Object pk, boolean required) {
0788:                    /*
0789:                    Row cursor = clean;
0790:                    while(cursor != null)
0791:                    {
0792:                       if(pk.equals(cursor.pk))
0793:                       {
0794:                          return cursor;
0795:                       }
0796:                       cursor = cursor.next;
0797:                    }
0798:
0799:                    cursor = dirty;
0800:                    while(cursor != null)
0801:                    {
0802:                       if(pk.equals(cursor.pk))
0803:                       {
0804:                          return cursor;
0805:                       }
0806:                       cursor = cursor.next;
0807:                    }
0808:
0809:                    cursor = created;
0810:                    while(cursor != null)
0811:                    {
0812:                       if(pk.equals(cursor.pk))
0813:                       {
0814:                          return cursor;
0815:                       }
0816:                       cursor = cursor.next;
0817:                    }
0818:                     */
0819:
0820:                    Row row = (Row) rowByPk.get(pk);
0821:
0822:                    if (row == null) {
0823:                        Object[] fields;
0824:                        Object[] relations = null;
0825:                        try {
0826:                            cache.lock(pk);
0827:
0828:                            fields = cache.getFields(pk);
0829:                            if (fields != null && relationsTotal > 0) {
0830:                                relations = cache.getRelations(pk);
0831:                                if (relations == null) {
0832:                                    relations = new Object[relationsTotal];
0833:                                }
0834:                            }
0835:                        } finally {
0836:                            cache.unlock(pk);
0837:                        }
0838:
0839:                        if (fields != null) {
0840:                            row = createCleanRow(pk, fields, relations);
0841:                        }
0842:                    }
0843:
0844:                    if (row == null && required) {
0845:                        throw new IllegalStateException("row not found: pk="
0846:                                + pk);
0847:                    }
0848:
0849:                    return row;
0850:                }
0851:
0852:                public void addClean(Row row) {
0853:                    /*
0854:                    if(getRowByPk(row.pk, false) != null)
0855:                    {
0856:                       throw new IllegalStateException("View already contains the row: key=" + row.pk);
0857:                    }
0858:                     */
0859:
0860:                    if (clean != null) {
0861:                        row.next = clean;
0862:                        clean.prev = row;
0863:                    }
0864:
0865:                    clean = row;
0866:                    row.state = CLEAN;
0867:
0868:                    rowByPk.put(row.pk, row);
0869:                }
0870:
0871:                public void addCreated(Row row) throws DuplicateKeyException {
0872:                    //if(getRowByPk(row.pk, false) != null)
0873:                    //{
0874:                    //   throw new DuplicateKeyException("Table " + tableName + ", key=" + row.pk);
0875:                    //}
0876:
0877:                    if (created != null) {
0878:                        row.next = created;
0879:                        created.prev = row;
0880:                    }
0881:
0882:                    created = row;
0883:                    row.state = CREATED;
0884:
0885:                    rowByPk.put(row.pk, row);
0886:
0887:                    JDBCCMPFieldBridge2 versionField = entity.getVersionField();
0888:                    if (versionField != null) {
0889:                        row.fields[versionField.getVersionIndex()] = row.fields[versionField
0890:                                .getRowIndex()];
0891:                    }
0892:                }
0893:
0894:                public Row loadRow(ResultSet rs, Object pk,
0895:                        boolean searchableOnly) {
0896:                    Row row = getRowByPk(pk, false);
0897:                    if (row != null) {
0898:                        if (log.isTraceEnabled()) {
0899:                            log.trace("row is already loaded: pk=" + pk);
0900:                        }
0901:                        return row;
0902:                    } else if (log.isTraceEnabled()) {
0903:                        log.trace("reading result set: pk=" + pk);
0904:                    }
0905:
0906:                    row = createCleanRow(pk);
0907:                    JDBCCMPFieldBridge2[] tableFields = (JDBCCMPFieldBridge2[]) entity
0908:                            .getTableFields();
0909:                    // this rsOffset is kind of a hack
0910:                    // but since tableIndex and rowIndex of a field are the same
0911:                    // this should work ok
0912:                    int rsOffset = 1;
0913:                    for (int i = 0; i < tableFields.length; ++i) {
0914:                        JDBCCMPFieldBridge2 field = tableFields[i];
0915:                        if (searchableOnly
0916:                                && !field.getJDBCType().isSearchable()) {
0917:                            row.fields[field.getRowIndex()] = NOT_LOADED;
0918:                            --rsOffset;
0919:                            continue;
0920:                        }
0921:
0922:                        Object columnValue = field.loadArgumentResults(rs,
0923:                                field.getRowIndex() + rsOffset);
0924:                        row.fields[field.getRowIndex()] = columnValue;
0925:
0926:                        if (field.getVersionIndex() != -1) {
0927:                            row.fields[field.getVersionIndex()] = columnValue;
0928:                        }
0929:                    }
0930:
0931:                    Object[] relations = (relationsTotal > 0 ? new Object[relationsTotal]
0932:                            : null);
0933:
0934:                    try {
0935:                        cache.lock(row.pk);
0936:                        cache.put(tx, row.pk, row.fields, relations);
0937:                    } finally {
0938:                        cache.unlock(row.pk);
0939:                    }
0940:
0941:                    return row;
0942:                }
0943:
0944:                public Object loadPk(ResultSet rs) {
0945:                    Object pk = null;
0946:                    JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity
0947:                            .getPrimaryKeyFields();
0948:                    //int rsInd = 1;
0949:                    for (int i = 0; i < pkFields.length; ++i) {
0950:                        JDBCCMPFieldBridge2 field = pkFields[i];
0951:                        //Object columnValue = field.loadArgumentResults(rs, rsInd++);
0952:                        Object columnValue = field.loadArgumentResults(rs,
0953:                                field.getRowIndex() + 1);
0954:                        pk = field.setPrimaryKeyValue(pk, columnValue);
0955:                    }
0956:                    return pk;
0957:                }
0958:
0959:                public boolean hasRow(Object id) {
0960:                    boolean has = rowByPk.containsKey(id);
0961:                    if (!has) {
0962:                        try {
0963:                            cache.lock(id);
0964:                            has = cache.contains(tx, id);
0965:                        } finally {
0966:                            cache.unlock(id);
0967:                        }
0968:                    }
0969:                    return has;
0970:                }
0971:
0972:                public void addRowWithNullFk(Row row) {
0973:                    if (rowsWithNullFks == null) {
0974:                        rowsWithNullFks = new ArrayList();
0975:                    }
0976:                    rowsWithNullFks.add(row);
0977:                }
0978:
0979:                private Row createCleanRow(Object pk) {
0980:                    Row row = new Row(this );
0981:                    row.pk = pk;
0982:                    addClean(row);
0983:                    return row;
0984:                }
0985:
0986:                private Row createCleanRow(Object pk, Object[] fields,
0987:                        Object[] relations) {
0988:                    Row row = new Row(this , fields, relations);
0989:                    row.pk = pk;
0990:                    addClean(row);
0991:                    return row;
0992:                }
0993:
0994:                // Table.View implementation
0995:
0996:                public void flushDeleted(Schema.Views views)
0997:                        throws SQLException {
0998:                    if (rowsWithNullFks != null) {
0999:                        nullifyForeignKeys();
1000:                        rowsWithNullFks = null;
1001:                    }
1002:
1003:                    if (deleted == null) {
1004:                        if (log.isTraceEnabled()) {
1005:                            log.trace("no rows to delete");
1006:                        }
1007:                        return;
1008:                    }
1009:
1010:                    if (referencedBy != null) {
1011:                        if (inFlush) {
1012:                            if (log.isTraceEnabled()) {
1013:                                log.trace("inFlush, ignoring flushDeleted");
1014:                            }
1015:                            return;
1016:                        }
1017:
1018:                        inFlush = true;
1019:
1020:                        try {
1021:                            for (int i = 0; i < referencedBy.length; ++i) {
1022:                                final Table.View view = views.entityViews[referencedBy[i]];
1023:                                if (view != null) {
1024:                                    view.flushDeleted(views);
1025:                                }
1026:                            }
1027:                        } finally {
1028:                            inFlush = false;
1029:                        }
1030:                    }
1031:
1032:                    delete(this );
1033:                }
1034:
1035:                public void flushCreated(Schema.Views views)
1036:                        throws SQLException {
1037:                    if (created == null || dontFlushCreated) {
1038:                        if (log.isTraceEnabled()) {
1039:                            log.trace("no rows to insert");
1040:                        }
1041:                        return;
1042:                    }
1043:
1044:                    if (references != null) {
1045:                        if (inFlush) {
1046:                            if (log.isTraceEnabled()) {
1047:                                log.trace("inFlush, ignorning flushCreated");
1048:                            }
1049:                            return;
1050:                        } else if (log.isTraceEnabled()) {
1051:                            log.trace("flushing created references");
1052:                        }
1053:
1054:                        inFlush = true;
1055:                        try {
1056:                            for (int i = 0; i < references.length; ++i) {
1057:                                final Table.View view = views.entityViews[references[i]];
1058:                                if (view != null) {
1059:                                    view.flushCreated(views);
1060:                                }
1061:                            }
1062:                        } finally {
1063:                            inFlush = false;
1064:                        }
1065:                    }
1066:
1067:                    insert(this );
1068:                }
1069:
1070:                public void flushUpdated() throws SQLException {
1071:                    if (dirtyRelations != null) {
1072:                        while (dirtyRelations != null) {
1073:                            Row row = dirtyRelations;
1074:                            row.flushStatus();
1075:                        }
1076:                    }
1077:
1078:                    if (dirty == null) {
1079:                        if (log.isTraceEnabled()) {
1080:                            log.trace("no rows to update");
1081:                        }
1082:                        return;
1083:                    }
1084:
1085:                    update(this );
1086:                }
1087:
1088:                public void beforeCompletion() {
1089:                    /* There is no sense in the current impl of lock-for-update.
1090:                    if(cacheUpdates != null)
1091:                    {
1092:                       Row cursor = cacheUpdates;
1093:
1094:                       while(cursor != null)
1095:                       {
1096:                          cache.lock(cursor.pk);
1097:                          try
1098:                          {
1099:                             cache.lockForUpdate(tx, cursor.pk);
1100:                          }
1101:                          catch(Exception e)
1102:                          {
1103:                             throw new EJBException("Table " + entity.getQualifiedTableName() + ": " + e.getMessage());
1104:                          }
1105:                          finally
1106:                          {
1107:                             cache.unlock(cursor.pk);
1108:                          }
1109:
1110:                          cursor.lockedForUpdate = true;
1111:                          cursor = cursor.nextCacheUpdate;
1112:                       }
1113:                    }
1114:                     */
1115:                }
1116:
1117:                public void committed() {
1118:                    if (cacheUpdates != null) {
1119:                        Row cursor = cacheUpdates;
1120:
1121:                        while (cursor != null) {
1122:                            //if(cursor.lockedForUpdate)
1123:                            //{
1124:                            cache.lock(cursor.pk);
1125:                            try {
1126:                                switch (cursor.state) {
1127:                                case CLEAN:
1128:                                    cache.put(tx, cursor.pk, cursor.fields,
1129:                                            cursor.relations);
1130:                                    break;
1131:                                case DELETED:
1132:                                    try {
1133:                                        cache.remove(tx, cursor.pk);
1134:                                    } catch (Cache.RemoveException e) {
1135:                                        log.warn(e.getMessage());
1136:                                    }
1137:                                    break;
1138:                                default:
1139:                                    throw new IllegalStateException(
1140:                                            "Unexpected row state: table="
1141:                                                    + entity
1142:                                                            .getQualifiedTableName()
1143:                                                    + ", pk=" + cursor.pk
1144:                                                    + ", state=" + cursor.state);
1145:                                }
1146:                            } finally {
1147:                                cache.unlock(cursor.pk);
1148:                            }
1149:                            //cursor.lockedForUpdate = false;
1150:                            //}
1151:                            cursor = cursor.nextCacheUpdate;
1152:                        }
1153:                    }
1154:                }
1155:
1156:                public void rolledback() {
1157:                    /* There is no sense in the current impl of lock-for-update.
1158:                    if(cacheUpdates != null)
1159:                    {
1160:                       Row cursor = cacheUpdates;
1161:
1162:                       while(cursor != null)
1163:                       {
1164:                          if(cursor.lockedForUpdate)
1165:                          {
1166:                             cache.lock(cursor.pk);
1167:                             try
1168:                             {
1169:                                cache.releaseLock(tx, cursor.pk);
1170:                             }
1171:                             catch(Exception e)
1172:                             {
1173:                                log.warn("Table " + entity.getQualifiedTableName() + ": " + e.getMessage());
1174:                             }
1175:                             finally
1176:                             {
1177:                                cache.unlock(cursor.pk);
1178:                             }
1179:                             cursor.lockedForUpdate = false;
1180:                          }
1181:                          cursor = cursor.nextCacheUpdate;
1182:                       }
1183:                    }
1184:                     */
1185:                }
1186:
1187:                private void nullifyForeignKeys() throws SQLException {
1188:                    if (log.isTraceEnabled()) {
1189:                        log.trace("nullifying foreign keys");
1190:                    }
1191:
1192:                    Connection con = null;
1193:                    PreparedStatement[] ps = new PreparedStatement[fkConstraints.length];
1194:
1195:                    try {
1196:                        final JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity
1197:                                .getPrimaryKeyFields();
1198:                        con = dataSource.getConnection();
1199:
1200:                        for (int i = 0; i < rowsWithNullFks.size(); ++i) {
1201:                            final Row row = (Row) rowsWithNullFks.get(i);
1202:                            if (row.state != DELETED) {
1203:                                final ForeignKeyConstraint[] cons = row.fkUpdates;
1204:                                for (int c = 0; c < fkConstraints.length; ++c) {
1205:                                    if (cons[c] != null) {
1206:                                        PreparedStatement s = ps[c];
1207:                                        if (s == null) {
1208:                                            if (log.isDebugEnabled()) {
1209:                                                log.debug("nullifying fk: "
1210:                                                        + cons[c].nullFkSql);
1211:                                            }
1212:                                            s = con
1213:                                                    .prepareStatement(cons[c].nullFkSql);
1214:                                            ps[c] = s;
1215:                                        }
1216:
1217:                                        int paramInd = 1;
1218:                                        for (int fInd = 0; fInd < pkFields.length; ++fInd) {
1219:                                            JDBCCMPFieldBridge2 pkField = pkFields[fInd];
1220:                                            Object fieldValue = row.fields[pkField
1221:                                                    .getRowIndex()];
1222:                                            paramInd = pkField
1223:                                                    .setArgumentParameters(s,
1224:                                                            paramInd,
1225:                                                            fieldValue);
1226:                                        }
1227:
1228:                                        final int affected = s.executeUpdate();
1229:                                        if (affected != 1) {
1230:                                            throw new EJBException(
1231:                                                    "Affected "
1232:                                                            + affected
1233:                                                            + " rows while expected just one");
1234:                                        }
1235:                                    }
1236:                                }
1237:                            }
1238:                        }
1239:                    } finally {
1240:                        for (int i = 0; i < ps.length; ++i) {
1241:                            JDBCUtil.safeClose(ps[i]);
1242:                        }
1243:                        JDBCUtil.safeClose(con);
1244:                    }
1245:                }
1246:            }
1247:
1248:            public class Row {
1249:                private EntityTable.View view;
1250:                private Object pk;
1251:                private final Object[] fields;
1252:                private final Object[] relations;
1253:
1254:                private byte state;
1255:
1256:                private Row prev;
1257:                private Row next;
1258:
1259:                private boolean cacheUpdateScheduled;
1260:                private Row nextCacheUpdate;
1261:                //private boolean lockedForUpdate;
1262:
1263:                private ForeignKeyConstraint[] fkUpdates;
1264:
1265:                public Row(EntityTable.View view) {
1266:                    this .view = view;
1267:                    fields = new Object[fieldsTotal];
1268:                    relations = (relationsTotal == 0 ? null
1269:                            : new Object[relationsTotal]);
1270:                    state = UNREFERENCED;
1271:                }
1272:
1273:                public Row(EntityTable.View view, Object[] fields,
1274:                        Object[] relations) {
1275:                    this .view = view;
1276:                    this .fields = fields;
1277:                    this .relations = relations;
1278:                    state = UNREFERENCED;
1279:                }
1280:
1281:                public Object getPk() {
1282:                    return pk;
1283:                }
1284:
1285:                public void loadCachedRelations(int index,
1286:                        Cache.CacheLoader loader) {
1287:                    if (relations != null) {
1288:                        final Object cached = relations[index];
1289:                        relations[index] = loader.loadFromCache(cached);
1290:                    }
1291:                }
1292:
1293:                public void cacheRelations(int index, Cache.CacheLoader loader) {
1294:                    relations[index] = loader.getCachedValue();
1295:                    scheduleCacheUpdate();
1296:                }
1297:
1298:                public void insert(Object pk) throws DuplicateKeyException {
1299:                    this .pk = pk;
1300:                    view.addCreated(this );
1301:                }
1302:
1303:                public Object getFieldValue(int i) {
1304:                    if (state == DELETED) {
1305:                        throw new NoSuchObjectLocalException(
1306:                                "The instance was removed: " + pk);
1307:                    }
1308:
1309:                    Object value = fields[i];
1310:                    if (value == NOT_LOADED) {
1311:                        value = loadField(i);
1312:                    }
1313:
1314:                    return value;
1315:                }
1316:
1317:                public void setFieldValue(int i, Object value) {
1318:                    fields[i] = value;
1319:                }
1320:
1321:                public boolean isDirty() {
1322:                    return state != CLEAN && state != DIRTY_RELATIONS;
1323:                }
1324:
1325:                public void setDirty() {
1326:                    if (state == CLEAN || state == DIRTY_RELATIONS) {
1327:                        updateState(DIRTY);
1328:                    }
1329:                }
1330:
1331:                public void setDirtyRelations() {
1332:                    if (state == CLEAN) {
1333:                        updateState(DIRTY_RELATIONS);
1334:                    }
1335:                }
1336:
1337:                public void delete() {
1338:                    if (state == CLEAN || state == DIRTY
1339:                            || state == DIRTY_RELATIONS) {
1340:                        updateState(DELETED);
1341:                    } else if (state == CREATED) {
1342:                        dereference();
1343:                        state = DELETED;
1344:                        view.rowByPk.remove(pk);
1345:                    } else if (state == DELETED) {
1346:                        throw new IllegalStateException(
1347:                                "The row is already deleted: pk=" + pk);
1348:                    }
1349:                }
1350:
1351:                public void nullForeignKey(ForeignKeyConstraint constraint) {
1352:                    if (fkUpdates == null) {
1353:                        fkUpdates = new ForeignKeyConstraint[fkConstraints.length];
1354:                        view.addRowWithNullFk(this );
1355:                    }
1356:
1357:                    fkUpdates[constraint.index] = constraint;
1358:                }
1359:
1360:                public void nonNullForeignKey(ForeignKeyConstraint constraint) {
1361:                    if (fkUpdates != null) {
1362:                        fkUpdates[constraint.index] = null;
1363:                    }
1364:                }
1365:
1366:                private void flushStatus() {
1367:                    if (state == CREATED || state == DIRTY) {
1368:                        updateState(CLEAN);
1369:                    } else if (state == DELETED) {
1370:                        dereference();
1371:                    } else if (state == DIRTY_RELATIONS) {
1372:                        updateState(CLEAN);
1373:                    }
1374:
1375:                    scheduleCacheUpdate();
1376:                }
1377:
1378:                private void scheduleCacheUpdate() {
1379:                    if (!cacheUpdateScheduled) {
1380:                        if (view.cacheUpdates == null) {
1381:                            view.cacheUpdates = this ;
1382:                        } else {
1383:                            nextCacheUpdate = view.cacheUpdates;
1384:                            view.cacheUpdates = this ;
1385:                        }
1386:                        cacheUpdateScheduled = true;
1387:                    }
1388:                }
1389:
1390:                private void updateState(byte state) {
1391:                    dereference();
1392:
1393:                    if (state == CLEAN) {
1394:                        if (view.clean != null) {
1395:                            next = view.clean;
1396:                            view.clean.prev = this ;
1397:                        }
1398:                        view.clean = this ;
1399:                    } else if (state == DIRTY) {
1400:                        if (view.dirty != null) {
1401:                            next = view.dirty;
1402:                            view.dirty.prev = this ;
1403:                        }
1404:                        view.dirty = this ;
1405:                    } else if (state == CREATED) {
1406:                        if (view.created != null) {
1407:                            next = view.created;
1408:                            view.created.prev = this ;
1409:                        }
1410:                        view.created = this ;
1411:                    } else if (state == DELETED) {
1412:                        if (view.deleted != null) {
1413:                            next = view.deleted;
1414:                            view.deleted.prev = this ;
1415:                        }
1416:                        view.deleted = this ;
1417:                    } else if (state == DIRTY_RELATIONS) {
1418:                        if (view.dirtyRelations != null) {
1419:                            next = view.dirtyRelations;
1420:                            view.dirtyRelations.prev = this ;
1421:                        }
1422:                        view.dirtyRelations = this ;
1423:                    } else {
1424:                        throw new IllegalStateException(
1425:                                "Can't update to state: " + state);
1426:                    }
1427:
1428:                    this .state = state;
1429:                }
1430:
1431:                private void dereference() {
1432:                    if (state == CLEAN && view.clean == this ) {
1433:                        view.clean = next;
1434:                    } else if (state == DIRTY && view.dirty == this ) {
1435:                        view.dirty = next;
1436:                    } else if (state == CREATED && view.created == this ) {
1437:                        view.created = next;
1438:                    } else if (state == DELETED && view.deleted == this ) {
1439:                        view.deleted = next;
1440:                    } else if (state == DIRTY_RELATIONS
1441:                            && view.dirtyRelations == this ) {
1442:                        view.dirtyRelations = next;
1443:                    }
1444:
1445:                    if (next != null) {
1446:                        next.prev = prev;
1447:                    }
1448:
1449:                    if (prev != null) {
1450:                        prev.next = next;
1451:                    }
1452:
1453:                    prev = null;
1454:                    next = null;
1455:                }
1456:
1457:                public void flush() throws SQLException, DuplicateKeyException {
1458:                    // todo needs refactoring
1459:
1460:                    if (state != CREATED) {
1461:                        if (log.isTraceEnabled()) {
1462:                            log.trace("The row is already inserted: pk=" + pk);
1463:                        }
1464:                        return;
1465:                    }
1466:
1467:                    Connection con = null;
1468:                    PreparedStatement duplicatePkPs = null;
1469:                    PreparedStatement insertPs = null;
1470:                    ResultSet rs = null;
1471:                    try {
1472:                        int paramInd;
1473:                        con = dataSource.getConnection();
1474:
1475:                        // check for duplicate key
1476:                        /*
1477:                        if(log.isDebugEnabled())
1478:                        {
1479:                           log.debug("executing : " + duplicatePkSql);
1480:                        }
1481:
1482:                        duplicatePkPs = con.prepareStatement(duplicatePkSql);
1483:
1484:                        paramInd = 1;
1485:                        JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity.getPrimaryKeyFields();
1486:                        for(int i = 0; i < pkFields.length; ++i)
1487:                        {
1488:                           JDBCCMPFieldBridge2 pkField = pkFields[i];
1489:                           Object fieldValue = fields[pkField.getRowIndex()];
1490:                           paramInd = pkField.setArgumentParameters(duplicatePkPs, paramInd, fieldValue);
1491:                        }
1492:
1493:                        rs = duplicatePkPs.executeQuery();
1494:                        if(rs.next())
1495:                        {
1496:                           throw new DuplicateKeyException("Table " + tableName + ", pk=" + pk);
1497:                        }
1498:                         */
1499:
1500:                        // insert
1501:                        if (log.isDebugEnabled()) {
1502:                            log.debug("executing : " + insertSql);
1503:                        }
1504:
1505:                        insertPs = con.prepareStatement(insertSql);
1506:
1507:                        paramInd = 1;
1508:                        JDBCCMPFieldBridge2[] tableFields = (JDBCCMPFieldBridge2[]) entity
1509:                                .getTableFields();
1510:                        for (int fInd = 0; fInd < tableFields.length; ++fInd) {
1511:                            JDBCCMPFieldBridge2 field = tableFields[fInd];
1512:                            Object fieldValue = fields[field.getRowIndex()];
1513:                            paramInd = field.setArgumentParameters(insertPs,
1514:                                    paramInd, fieldValue);
1515:                        }
1516:
1517:                        insertPs.executeUpdate();
1518:
1519:                        flushStatus();
1520:                    } catch (SQLException e) {
1521:                        log.error("Failed to insert new rows: "
1522:                                + e.getMessage(), e);
1523:                        throw e;
1524:                    } finally {
1525:                        JDBCUtil.safeClose(rs);
1526:                        JDBCUtil.safeClose(duplicatePkPs);
1527:                        JDBCUtil.safeClose(insertPs);
1528:                        JDBCUtil.safeClose(con);
1529:                    }
1530:                }
1531:
1532:                private Object loadField(int i) {
1533:                    JDBCCMPFieldBridge2 field = (JDBCCMPFieldBridge2) entity
1534:                            .getFields().get(i);
1535:
1536:                    StringBuffer query = new StringBuffer();
1537:                    query.append("select ").append(field.getColumnName())
1538:                            .append(" from ").append(tableName).append(
1539:                                    " where ");
1540:
1541:                    JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity
1542:                            .getPrimaryKeyFields();
1543:                    for (int pkI = 0; pkI < pkFields.length; ++pkI) {
1544:                        if (pkI > 0) {
1545:                            query.append(" and ");
1546:                        }
1547:                        query.append(pkFields[pkI].getColumnName())
1548:                                .append("=?");
1549:                    }
1550:
1551:                    if (log.isDebugEnabled()) {
1552:                        log.debug("executing: " + query.toString());
1553:                    }
1554:
1555:                    Object value = null;
1556:                    Connection con = null;
1557:                    PreparedStatement ps = null;
1558:                    ResultSet rs = null;
1559:
1560:                    try {
1561:                        con = dataSource.getConnection();
1562:                        ps = con.prepareStatement(query.toString());
1563:
1564:                        for (int pkI = 0; pkI < pkFields.length; ++pkI) {
1565:                            JDBCCMPFieldBridge2 pkField = pkFields[pkI];
1566:                            Object fieldValue = fields[pkField.getRowIndex()];
1567:                            pkField.setArgumentParameters(ps, pkI + 1,
1568:                                    fieldValue);
1569:                        }
1570:
1571:                        rs = ps.executeQuery();
1572:
1573:                        if (!rs.next()) {
1574:                            throw new NoSuchEntityException("Row not found: "
1575:                                    + pk);
1576:                        }
1577:
1578:                        value = field.loadArgumentResults(rs, 1);
1579:                    } catch (SQLException e) {
1580:                        throw new EJBException("Failed to load field "
1581:                                + entity.getEntityName() + "."
1582:                                + field.getFieldName() + ": " + e.getMessage(),
1583:                                e);
1584:                    } finally {
1585:                        JDBCUtil.safeClose(rs);
1586:                        JDBCUtil.safeClose(ps);
1587:                        JDBCUtil.safeClose(con);
1588:                    }
1589:
1590:                    fields[field.getRowIndex()] = value;
1591:                    return value;
1592:                }
1593:            }
1594:
1595:            public static interface CommitStrategy {
1596:                void executeUpdate(PreparedStatement ps) throws SQLException;
1597:
1598:                void executeBatch(PreparedStatement ps) throws SQLException;
1599:            }
1600:
1601:            private static final CommitStrategy BATCH_UPDATE = new CommitStrategy() {
1602:                public void executeUpdate(PreparedStatement ps)
1603:                        throws SQLException {
1604:                    ps.addBatch();
1605:                }
1606:
1607:                public void executeBatch(PreparedStatement ps)
1608:                        throws SQLException {
1609:                    int[] updates = ps.executeBatch();
1610:                    for (int i = 0; i < updates.length; ++i) {
1611:                        int status = updates[i];
1612:                        if (status != 1 && status != -2 /* java.sql.Statement.SUCCESS_NO_INFO since jdk1.4*/) {
1613:                            String msg = (status == -3 /* java.sql.Statement.EXECUTE_FAILED since jdk1.4 */? "One of the commands in the batch failed to execute"
1614:                                    : "Each command in the batch should update exactly 1 row but "
1615:                                            + "one of the commands updated "
1616:                                            + updates[i] + " rows.");
1617:                            throw new EJBException(msg);
1618:                        }
1619:                    }
1620:                }
1621:            };
1622:
1623:            private static final CommitStrategy NON_BATCH_UPDATE = new CommitStrategy() {
1624:                public void executeUpdate(PreparedStatement ps)
1625:                        throws SQLException {
1626:                    int rows = ps.executeUpdate();
1627:                    if (rows != 1) {
1628:                        throw new EJBException(
1629:                                "Expected one updated row but got: " + rows);
1630:                    }
1631:                }
1632:
1633:                public void executeBatch(PreparedStatement ps) {
1634:                }
1635:            };
1636:
1637:            public class ForeignKeyConstraint {
1638:                public final int index;
1639:                private final String nullFkSql;
1640:
1641:                public ForeignKeyConstraint(int index,
1642:                        JDBCCMPFieldBridge2[] fkFields) {
1643:                    this .index = index;
1644:
1645:                    StringBuffer buf = new StringBuffer();
1646:                    buf.append("update ").append(tableName).append(" set ")
1647:                            .append(fkFields[0].getColumnName())
1648:                            .append("=null");
1649:                    for (int i = 1; i < fkFields.length; ++i) {
1650:                        buf.append(", ").append(fkFields[i].getColumnName())
1651:                                .append("=null");
1652:                    }
1653:
1654:                    buf.append(" where ");
1655:                    JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[]) entity
1656:                            .getPrimaryKeyFields();
1657:                    buf.append(pkFields[0].getColumnName()).append("=?");
1658:                    for (int i = 1; i < pkFields.length; ++i) {
1659:                        buf.append(" and ").append(pkFields[i].getColumnName())
1660:                                .append("=?");
1661:                    }
1662:
1663:                    nullFkSql = buf.toString();
1664:                    if (log.isDebugEnabled()) {
1665:                        log.debug("update foreign key sql: " + nullFkSql);
1666:                    }
1667:                }
1668:            }
1669:        }
w___w__w.___j_a_v___a__2s___.___c_o__m__ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.