Source Code Cross Referenced for ObjectSupport.java in  » Web-Framework » jWebApp » jpersist » 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 » Web Framework » jWebApp » jpersist 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**
0002:         * Copyright (C) 2006, 2007 David Bulmore, Software Sensation Inc.  
0003:         * All Rights Reserved.
0004:         *
0005:         * This file is part of JPersist.
0006:         *
0007:         * JPersist is free software; you can redistribute it and/or modify it under 
0008:         * the terms of the GNU General Public License (Version 2) as published by 
0009:         * the Free Software Foundation.
0010:         *
0011:         * JPersist is distributed in the hope that it will be useful, but WITHOUT 
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
0013:         * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
0014:         * for more details.
0015:         *
0016:         * You should have received a copy of the GNU General Public License 
0017:         * along with JPersist; if not, write to the Free Software Foundation, 
0018:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
0019:         */package jpersist;
0020:
0021:        import java.lang.reflect.Array;
0022:        import jcommontk.object.ObjectFiller;
0023:        import java.lang.reflect.InvocationTargetException;
0024:        import java.lang.reflect.Method;
0025:        import java.sql.SQLException;
0026:        import java.util.Collection;
0027:        import java.util.HashMap;
0028:        import java.util.HashSet;
0029:        import java.util.Iterator;
0030:        import java.util.Map;
0031:        import java.util.Set;
0032:        import java.util.Vector;
0033:        import java.util.logging.Level;
0034:        import java.util.logging.Logger;
0035:        import java.util.zip.CRC32;
0036:        import jcommontk.object.ObjectConverter;
0037:        import jcommontk.object.ObjectFiller.GetHandler;
0038:        import jcommontk.object.ObjectFiller.ItemNotFoundException;
0039:        import jcommontk.utils.StringUtils;
0040:        import jpersist.interfaces.ColumnMapping;
0041:        import jpersist.interfaces.GeneratedKeys;
0042:        import jpersist.annotations.GlobalDelete;
0043:        import jpersist.annotations.GlobalUpdate;
0044:        import jpersist.annotations.UpdateNullValues;
0045:        import jpersist.annotations.SingleTableInheritance;
0046:        import jpersist.annotations.ConcreteTableInheritance;
0047:
0048:        // TODO check parent id for null value
0049:        @SuppressWarnings("unchecked")
0050:        // working to complete a Java 1.5 version
0051:        final class ObjectSupport {
0052:            private static Logger logger = Logger.getLogger(ObjectSupport.class
0053:                    .getName());
0054:
0055:            static Result queryObject(Database db, Class cs, Object object,
0056:                    Set nullValuesToInclude, boolean idColumnsOnly,
0057:                    String externalClauses, Object[] parameters)
0058:                    throws JPersistException, SQLException,
0059:                    IllegalAccessException, InvocationTargetException {
0060:                if (logger.isLoggable(Level.FINER))
0061:                    logger.finer("Querying object: class " + cs.getName()
0062:                            + "\nexternalClauses = " + externalClauses
0063:                            + "\nparameters[] = "
0064:                            + StringUtils.toString(parameters)
0065:                            + "IdColumnsOnly = " + idColumnsOnly);
0066:
0067:                if (cs == null && object == null)
0068:                    throw new JPersistException("object is null");
0069:
0070:                StringBuffer sqlStatement = new StringBuffer(), externalClausesStrBuf = null;
0071:                Vector values = new Vector();
0072:
0073:                if (externalClauses == null
0074:                        || !externalClauses.startsWith("select")) {
0075:                    StringBuffer columnsStrBuf = new StringBuffer(), fromStrBuf = new StringBuffer(), whereStrBuf = new StringBuffer();
0076:
0077:                    if (externalClauses != null)
0078:                        externalClausesStrBuf = new StringBuffer(
0079:                                externalClauses);
0080:
0081:                    processClasses(db, cs, object, true, idColumnsOnly, false,
0082:                            false, nullValuesToInclude, new QueryObjectHandler(
0083:                                    db, fromStrBuf, columnsStrBuf, whereStrBuf,
0084:                                    externalClausesStrBuf, values));
0085:
0086:                    sqlStatement.append("select ").append(columnsStrBuf);
0087:
0088:                    if (externalClauses == null
0089:                            || !externalClauses.startsWith("from")) {
0090:                        sqlStatement.append(" from ").append(fromStrBuf);
0091:
0092:                        if (whereStrBuf.length() > 0) {
0093:                            if (externalClauses == null
0094:                                    || !externalClauses.startsWith("where"))
0095:                                sqlStatement.append(" where ").append(
0096:                                        whereStrBuf);
0097:                        } else if (idColumnsOnly)
0098:                            throw new JPersistException(
0099:                                    "useIdColumnsOnly is defined, but there are no Id field values available");
0100:                    }
0101:                }
0102:
0103:                if (externalClauses != null) {
0104:                    sqlStatement.append(" " + externalClausesStrBuf);
0105:
0106:                    if (parameters != null)
0107:                        for (int i = 0; i < parameters.length; i++)
0108:                            values.add(parameters[i]);
0109:                }
0110:
0111:                if (values.size() > 0)
0112:                    return db.parameterizedQuery(sqlStatement.toString(),
0113:                            values.toArray()).setClass(cs);
0114:                else
0115:                    return db.executeQuery(sqlStatement.toString())
0116:                            .setClass(cs);
0117:            }
0118:
0119:            static class QueryObjectHandler implements  ClassHandler {
0120:                Database db;
0121:                StringBuffer fromStrBuf, columnsStrBuf, whereStrBuf,
0122:                        externalClausesStrBuf;
0123:                String identifierQuoteString;
0124:                Set selectSet = new HashSet(), whereSet = new HashSet();
0125:                Map lastTable = new HashMap();
0126:                Vector values;
0127:
0128:                public QueryObjectHandler(Database db, StringBuffer fromStrBuf,
0129:                        StringBuffer columnsStrBuf, StringBuffer whereStrBuf,
0130:                        StringBuffer externalClausesStrBuf, Vector values)
0131:                        throws JPersistException {
0132:                    this .db = db;
0133:                    this .fromStrBuf = fromStrBuf;
0134:                    this .columnsStrBuf = columnsStrBuf;
0135:                    this .whereStrBuf = whereStrBuf;
0136:                    this .externalClausesStrBuf = externalClausesStrBuf;
0137:                    this .values = values;
0138:
0139:                    this .identifierQuoteString = db.getMetaData()
0140:                            .getIdentifierQuoteString();
0141:                }
0142:
0143:                public void processClass(Class objectClass, Object object,
0144:                        MetaData.Table table, int numberTables,
0145:                        char tableAlias, Map valuesMap, Set selectableColumns)
0146:                        throws JPersistException, SQLException,
0147:                        IllegalAccessException, InvocationTargetException {
0148:                    fromStrBuf.append((fromStrBuf.length() > 0 ? ", " : "")
0149:                            + identifierQuoteString + table.getTableName()
0150:                            + identifierQuoteString);
0151:
0152:                    if (numberTables > 1)
0153:                        fromStrBuf.append(" " + tableAlias);
0154:
0155:                    if (externalClausesStrBuf != null)
0156:                        processExternalClauses(externalClausesStrBuf, table, db
0157:                                .getColumnMapper(), object,
0158:                                identifierQuoteString);
0159:
0160:                    processSelect(selectableColumns, table, numberTables,
0161:                            tableAlias);
0162:                    processWhere(valuesMap, table, numberTables, tableAlias);
0163:                    processJoin(objectClass, table, numberTables, tableAlias);
0164:                }
0165:
0166:                void processSelect(Set selectableColumns, MetaData.Table table,
0167:                        int numberTables, char tableAlias) {
0168:                    for (Iterator it = selectableColumns.iterator(); it
0169:                            .hasNext();) {
0170:                        MetaData.Table.Column column = (MetaData.Table.Column) it
0171:                                .next();
0172:                        MetaData.Table.Key key = (MetaData.Table.Key) table
0173:                                .getImportedKeys().get(column.getColumnName());
0174:
0175:                        if (!selectSet.contains(column.getColumnName())
0176:                                && (key == null || !selectSet.contains(key
0177:                                        .getForeignColumnName()))) {
0178:                            selectSet.add(column.getColumnName());
0179:
0180:                            if (columnsStrBuf.length() > 0)
0181:                                columnsStrBuf.append(", ");
0182:
0183:                            if (numberTables > 1)
0184:                                columnsStrBuf.append(tableAlias + ".");
0185:
0186:                            columnsStrBuf.append(identifierQuoteString
0187:                                    + column.getColumnName()
0188:                                    + identifierQuoteString);
0189:                        }
0190:                    }
0191:                }
0192:
0193:                void processWhere(Map valuesMap, MetaData.Table table,
0194:                        int numberTables, char tableAlias) {
0195:                    for (Iterator it = valuesMap.entrySet().iterator(); it
0196:                            .hasNext();) {
0197:                        Map.Entry entry = (Map.Entry) it.next();
0198:                        MetaData.Table.Column column = (MetaData.Table.Column) entry
0199:                                .getKey();
0200:                        MetaData.Table.Key key = (MetaData.Table.Key) table
0201:                                .getImportedKeys().get(column.getColumnName());
0202:
0203:                        if (!whereSet.contains(column.getColumnName())
0204:                                && column.isSearchable()
0205:                                && (key == null || !whereSet.contains(key
0206:                                        .getForeignColumnName()))) {
0207:                            whereSet.add(column.getColumnName());
0208:
0209:                            if (whereStrBuf.length() > 0)
0210:                                whereStrBuf.append(" and ");
0211:
0212:                            if (numberTables > 1)
0213:                                whereStrBuf.append(tableAlias + ".");
0214:
0215:                            Object obj = entry.getValue();
0216:
0217:                            if (obj instanceof  NullValue)
0218:                                whereStrBuf.append(identifierQuoteString
0219:                                        + column.getColumnName()
0220:                                        + identifierQuoteString + " is null");
0221:                            else {
0222:                                values.add(obj);
0223:
0224:                                whereStrBuf
0225:                                        .append(identifierQuoteString
0226:                                                + column.getColumnName()
0227:                                                + identifierQuoteString
0228:                                                + (hasWildCards(obj.toString()) ? " like ?"
0229:                                                        : " = ?"));
0230:                            }
0231:                        }
0232:                    }
0233:                }
0234:
0235:                void processJoin(Class cs, MetaData.Table table,
0236:                        int numberTables, char tableAlias)
0237:                        throws JPersistException {
0238:                    if (numberTables > 1) {
0239:                        MetaData.Table last = (MetaData.Table) lastTable
0240:                                .get("table");
0241:
0242:                        if (last != null) {
0243:                            Set keys = getMatchingImportedExportedKeys(last
0244:                                    .getExportedKeys(), table.getImportedKeys());
0245:
0246:                            if (keys.size() == 0)
0247:                                throw new JPersistException(
0248:                                        "The inheritance relation represented by "
0249:                                                + cs.getName()
0250:                                                + " does not have primary/foreign key relationships defined for the underlying"
0251:                                                + " tables (must have a FOREIGN KEY ... REFERENCES ... clause in table creation, see alter table)");
0252:
0253:                            for (Iterator it2 = keys.iterator(); it2.hasNext();) {
0254:                                MetaData.Table.Key key = (MetaData.Table.Key) it2
0255:                                        .next();
0256:
0257:                                whereStrBuf
0258:                                        .append((whereStrBuf.length() > 0 ? " and "
0259:                                                : "")
0260:                                                + (char) (tableAlias - 1)
0261:                                                + "."
0262:                                                + identifierQuoteString
0263:                                                + key.getForeignColumnName()
0264:                                                + identifierQuoteString
0265:                                                + " = "
0266:                                                + tableAlias
0267:                                                + "."
0268:                                                + identifierQuoteString
0269:                                                + key.getLocalColumnName()
0270:                                                + identifierQuoteString);
0271:                            }
0272:                        }
0273:
0274:                        lastTable.put("table", table);
0275:                    }
0276:                }
0277:            }
0278:
0279:            static Object loadObject(Result result, Object object,
0280:                    boolean loadAssociations) throws JPersistException,
0281:                    SQLException, IllegalAccessException,
0282:                    InstantiationException, InvocationTargetException {
0283:                if (logger.isLoggable(Level.FINER))
0284:                    logger.finer("Loading object of class "
0285:                            + object.getClass().getName());
0286:
0287:                if (object == null)
0288:                    throw new JPersistException("data object is null");
0289:
0290:                if (object instanceof  PersistentObject)
0291:                    ((PersistentObject) object).makeObjectTransient();
0292:
0293:                processClasses(result.getDatabase(), object.getClass(), object,
0294:                        false, false, false, false, null, new LoadClassHandler(
0295:                                result, object));
0296:
0297:                if (object instanceof  PersistentObject)
0298:                    ((PersistentObject) object)
0299:                            .setObjectChecksum(calculateChecksum(result
0300:                                    .getDatabase(), object));
0301:
0302:                if (loadAssociations)
0303:                    if (!(object instanceof  PersistentObject && ((PersistentObject) object)
0304:                            .getIgnoreAssociations()))
0305:                        loadAssociations(result.getDatabase(), object);
0306:
0307:                return object;
0308:            }
0309:
0310:            static class LoadClassHandler implements  ClassHandler {
0311:                Result result;
0312:                Object object;
0313:
0314:                LoadClassHandler(Result result, Object object) {
0315:                    this .result = result;
0316:                    this .object = object;
0317:                }
0318:
0319:                public void processClass(Class objectClass,
0320:                        final Object object, final MetaData.Table table,
0321:                        int numberTables, final char tableAlias, Map valuesMap,
0322:                        Set selectableColumns) throws JPersistException,
0323:                        SQLException, IllegalAccessException,
0324:                        InvocationTargetException {
0325:                    if (objectClass
0326:                            .isAnnotationPresent(SingleTableInheritance.class)
0327:                            || objectClass
0328:                                    .isAnnotationPresent(ConcreteTableInheritance.class))
0329:                        objectClass = null;
0330:
0331:                    if (table != null)
0332:                        loadObjectsWithTableHelp(objectClass, object, table,
0333:                                tableAlias);
0334:                    else
0335:                        loadObjectsWithoutTableHelp(objectClass, object);
0336:                }
0337:
0338:                void loadObjectsWithTableHelp(Class objectClass,
0339:                        final Object object, final MetaData.Table table,
0340:                        final char tableAlias) throws IllegalAccessException,
0341:                        InvocationTargetException, JPersistException {
0342:                    if (object instanceof  PersistentObject)
0343:                        if (table.getPrimaryKeys().size() == 0)
0344:                            ((PersistentObject) object)
0345:                                    .setObjectPersistence(PersistentObject.MISSING_ROW_ID);
0346:
0347:                    ObjectFiller.fillObject(new GetHandler() {
0348:                        public Object get(String key, Class objectType)
0349:                                throws ItemNotFoundException {
0350:                            try {
0351:                                MetaData.Table.Column column = table.getColumn(
0352:                                        result.getDatabase().getColumnMapper(),
0353:                                        key, object);
0354:
0355:                                if (column != null) {
0356:                                    String columnName = column.getColumnName();
0357:                                    Object value = null;
0358:
0359:                                    try {
0360:                                        value = result.getColumnValue(
0361:                                                objectType, columnName);
0362:                                    } catch (Exception e) {
0363:                                        value = result.getColumnValue(
0364:                                                objectType, tableAlias + "."
0365:                                                        + columnName);
0366:                                    }
0367:
0368:                                    return value;
0369:                                }
0370:                            } catch (Exception e) {
0371:                                logger.log(Level.WARNING, e.toString(), e);
0372:                            }
0373:
0374:                            throw new ObjectFiller.ItemNotFoundException();
0375:                        }
0376:                    }, object, objectClass, true, false, null, true);
0377:
0378:                    loadPrimaryKeys(table, tableAlias);
0379:                }
0380:
0381:                void loadPrimaryKeys(MetaData.Table table, char tableAlias)
0382:                        throws JPersistException {
0383:                    if (object instanceof  PersistentObject) {
0384:                        Set ids = new HashSet(table.getPrimaryKeys().keySet());
0385:
0386:                        for (Iterator it = ids.iterator(); it.hasNext();) {
0387:                            String columnName = (String) it.next();
0388:                            Object value = null;
0389:
0390:                            try {
0391:                                value = result.getColumnValue(columnName);
0392:                            } catch (Exception e) {
0393:                                value = result.getColumnValue(tableAlias + "."
0394:                                        + columnName);
0395:                            }
0396:
0397:                            ((PersistentObject) object).getObjectKeyValues()
0398:                                    .put(columnName, value);
0399:                        }
0400:                    }
0401:                }
0402:
0403:                void loadObjectsWithoutTableHelp(Class objectClass,
0404:                        final Object object) throws IllegalAccessException,
0405:                        InvocationTargetException {
0406:                    if (logger.isLoggable(Level.FINER))
0407:                        logger.finer("table not found for class "
0408:                                + object.getClass().getName());
0409:
0410:                    if (object instanceof  PersistentObject)
0411:                        ((PersistentObject) object)
0412:                                .setObjectPersistence(PersistentObject.NO_TABLE_INFO);
0413:
0414:                    ObjectFiller.fillObject(new GetHandler() {
0415:                        public Object get(String key, Class objectType) {
0416:                            MetaData metaData = null;
0417:                            Object obj = null;
0418:                            String name = null;
0419:
0420:                            try {
0421:                                metaData = result.getDatabase().getMetaData();
0422:
0423:                                name = key;
0424:                                name = metaData.getStoresCase() == MetaData.STORES_UNKNOWN
0425:                                        || metaData.getStoresCase() == MetaData.STORES_LOWERCASE ? name
0426:                                        .toUpperCase()
0427:                                        : name.toLowerCase();
0428:
0429:                                obj = result.getColumnValue(objectType, name);
0430:                            } catch (Exception e) {
0431:                                try {
0432:                                    name = key;
0433:                                    name = metaData.getStoresCase() == MetaData.STORES_UNKNOWN
0434:                                            || metaData.getStoresCase() == MetaData.STORES_LOWERCASE ? StringUtils
0435:                                            .camelCaseToUpperCaseUnderline(name)
0436:                                            : StringUtils
0437:                                                    .camelCaseToLowerCaseUnderline(name);
0438:
0439:                                    obj = result.getColumnValue(objectType,
0440:                                            name);
0441:                                } catch (Exception e2) {
0442:                                    logger.log(Level.WARNING, e2.getMessage(),
0443:                                            e2);
0444:                                }
0445:                            }
0446:
0447:                            return obj;
0448:                        }
0449:                    }, object, objectClass, true, false, null, true);
0450:                }
0451:            }
0452:
0453:            static void loadAssociations(Database db, Object object)
0454:                    throws JPersistException, SQLException,
0455:                    InstantiationException, IllegalAccessException,
0456:                    InvocationTargetException {
0457:                Class objectClass = object.getClass();
0458:                Method objectMethods[] = objectClass.getMethods();
0459:
0460:                for (int i = 0; i < objectMethods.length; i++) {
0461:                    if (objectMethods[i].getName().equals("setDbAssociation")) {
0462:                        Class objectClass2 = objectMethods[i]
0463:                                .getParameterTypes()[0], c2Type = objectClass2
0464:                                .isArray() ? objectClass2.getComponentType()
0465:                                : objectClass2, collectionType = null;
0466:
0467:                        if (!(object instanceof  PersistentObject)
0468:                                || !((PersistentObject) object)
0469:                                        .classInIgnoreAssociation(c2Type)) {
0470:                            Method associationObjectMethods[] = c2Type
0471:                                    .getMethods();
0472:
0473:                            if (objectMethods[i].getParameterTypes().length == 2)
0474:                                collectionType = objectMethods[i]
0475:                                        .getParameterTypes()[1];
0476:
0477:                            Object associationObject = c2Type.newInstance();
0478:
0479:                            copyAssociationIds(db, object, associationObject);
0480:
0481:                            Result result2 = db.queryObject(associationObject);
0482:
0483:                            try {
0484:                                if (collectionType == null) {
0485:                                    if (!objectClass2.isArray()
0486:                                            && result2.hasNext()) {
0487:                                        Object obj = result2.next();
0488:
0489:                                        if (obj != null)
0490:                                            objectMethods[i].invoke(object,
0491:                                                    new Object[] { obj });
0492:                                    } else {
0493:                                        Vector tmp = new Vector();
0494:
0495:                                        while (result2.hasNext())
0496:                                            tmp.add(result2.next());
0497:
0498:                                        if (tmp.size() > 0)
0499:                                            objectMethods[i]
0500:                                                    .invoke(
0501:                                                            object,
0502:                                                            new Object[] { tmp
0503:                                                                    .toArray((Object[]) Array
0504:                                                                            .newInstance(
0505:                                                                                    c2Type,
0506:                                                                                    tmp
0507:                                                                                            .size())) });
0508:                                    }
0509:                                } else {
0510:                                    Collection collection = (Collection) collectionType
0511:                                            .newInstance();
0512:
0513:                                    while (result2.hasNext())
0514:                                        collection.add(result2.next());
0515:
0516:                                    if (collection.size() > 0)
0517:                                        objectMethods[i]
0518:                                                .invoke(object, new Object[] {
0519:                                                        null, collection });
0520:                                }
0521:                            } finally {
0522:                                result2.close();
0523:                            }
0524:                        }
0525:                    }
0526:                }
0527:            }
0528:
0529:            static int objectTransaction(Database db, Object object,
0530:                    Set nullValuesToInclude, boolean isInsertUpdate,
0531:                    String externalClauses, Object[] parameters)
0532:                    throws JPersistException, SQLException,
0533:                    IllegalAccessException, InvocationTargetException,
0534:                    InstantiationException {
0535:                if (object == null)
0536:                    throw new JPersistException("object is null");
0537:
0538:                int returnValue = 0;
0539:                boolean commit = false, rollback = false;
0540:
0541:                if (db.getAutoCommit()) {
0542:                    db.setAutoCommit(false);
0543:                    commit = true;
0544:                }
0545:
0546:                try {
0547:                    if (isInsertUpdate)
0548:                        returnValue = saveObject(db, object,
0549:                                nullValuesToInclude, externalClauses,
0550:                                parameters);
0551:                    else
0552:                        returnValue = deleteObject(db, object,
0553:                                nullValuesToInclude, externalClauses,
0554:                                parameters);
0555:                } catch (Exception e) {
0556:                    rollback = true;
0557:
0558:                    if (commit)
0559:                        db.rollback();
0560:
0561:                    throw new JPersistException(e);
0562:                } finally {
0563:                    if (commit) {
0564:                        if (!rollback)
0565:                            db.commit();
0566:
0567:                        db.setAutoCommit(true);
0568:                    }
0569:
0570:                    if (!rollback && isInsertUpdate
0571:                            && object instanceof  PersistentObject
0572:                            && ((PersistentObject) object).getReloadAfterSave()) {
0573:                        try {
0574:                            Result result = queryObject(db, object.getClass(),
0575:                                    object, null, true, null, (Object[]) null);
0576:
0577:                            try {
0578:                                if (result.hasNext())
0579:                                    result.next(object);
0580:                            } finally {
0581:                                result.close();
0582:                            }
0583:                        } catch (Exception e) {
0584:                            String message = "Could not reload object following save.  Can not make this object persistent.";
0585:
0586:                            if (e.getMessage() != null
0587:                                    && e.getMessage().startsWith(
0588:                                            "useIdColumnsOnly")
0589:                                    && !db.getMetaData()
0590:                                            .supportsGeneratedKeys()) {
0591:                                message += "\nYour database reports that it does not support retrieving auto-generated keys."
0592:                                        + "\nTherefore, you can't make objects relying on auto-generated keys persistent following an insert."
0593:                                        + "\nIn this case, only loaded objects can be persistent.  You can either implement GeneratedKeys or set "
0594:                                        + "PersistentObject.setReloadAfterSave(false)";
0595:                            }
0596:
0597:                            throw new JPersistException(message, e);
0598:                        }
0599:                    }
0600:                }
0601:
0602:                return returnValue;
0603:            }
0604:
0605:            static int saveObject(Database db, Object object,
0606:                    Set nullValuesToInclude, String externalClauses,
0607:                    Object[] parameters) throws JPersistException,
0608:                    SQLException, IllegalAccessException,
0609:                    InvocationTargetException, InstantiationException {
0610:                int returnValue = 0;
0611:                boolean persistentUpdate = (object instanceof  PersistentObject
0612:                        && ((PersistentObject) object).getObjectChecksum() != 0 && ((PersistentObject) object)
0613:                        .getObjectPersistence() == PersistentObject.OBJECT_CAN_PERSIST), externalWhere = (externalClauses != null && externalClauses
0614:                        .toLowerCase().startsWith("where")), globalUpdate = object
0615:                        .getClass().isAnnotationPresent(GlobalUpdate.class);
0616:
0617:                if (persistentUpdate || globalUpdate || externalWhere) {
0618:                    if (globalUpdate
0619:                            || externalWhere
0620:                            || ((PersistentObject) object).objectHasChanged()
0621:                            || calculateChecksum(db, object) != ((PersistentObject) object)
0622:                                    .getObjectChecksum())
0623:                        returnValue = updateObject(db, object,
0624:                                nullValuesToInclude, externalClauses,
0625:                                parameters);
0626:                } else
0627:                    returnValue = insertObject(db, object);
0628:
0629:                returnValue += saveAssociations(db, object);
0630:
0631:                return returnValue;
0632:            }
0633:
0634:            static int saveAssociations(Database db, Object object)
0635:                    throws JPersistException, SQLException,
0636:                    IllegalAccessException, InvocationTargetException,
0637:                    InstantiationException {
0638:                Method methods[] = object.getClass().getMethods();
0639:                boolean isPersistentObject = object instanceof  PersistentObject;
0640:                int returnValue = 0;
0641:
0642:                for (int i = 0; i < methods.length; i++) {
0643:                    if (methods[i].getName().equals("getDbAssociation")) {
0644:                        Object associationObject = methods[i].invoke(object,
0645:                                new Object[] { null });
0646:
0647:                        if (associationObject != null)
0648:                            if (associationObject instanceof  Collection) {
0649:                                Iterator it = ((Collection) associationObject)
0650:                                        .iterator();
0651:                                Object obj = null;
0652:
0653:                                while (it.hasNext()
0654:                                        && (obj = it.next()) != null) {
0655:                                    if (!(isPersistentObject && ((PersistentObject) object)
0656:                                            .classInIgnoreAssociation(obj
0657:                                                    .getClass()))) {
0658:                                        copyAssociationIds(db, object, obj);
0659:                                        returnValue += saveObject(db, obj,
0660:                                                null, null, null);
0661:                                    }
0662:                                }
0663:                            } else if (associationObject.getClass().isArray()) {
0664:                                Object objectArray[] = (Object[]) associationObject;
0665:
0666:                                for (int i2 = 0; i2 < objectArray.length; i2++) {
0667:                                    if (!(isPersistentObject && ((PersistentObject) object)
0668:                                            .classInIgnoreAssociation(objectArray[i2]
0669:                                                    .getClass()))) {
0670:                                        copyAssociationIds(db, object,
0671:                                                objectArray[i2]);
0672:                                        returnValue += saveObject(db,
0673:                                                objectArray[i2], null, null,
0674:                                                null);
0675:                                    }
0676:                                }
0677:                            } else {
0678:                                if (!(isPersistentObject && ((PersistentObject) object)
0679:                                        .classInIgnoreAssociation(associationObject
0680:                                                .getClass()))) {
0681:                                    copyAssociationIds(db, object,
0682:                                            associationObject);
0683:                                    returnValue = saveObject(db,
0684:                                            associationObject, null, null, null);
0685:                                }
0686:                            }
0687:                    }
0688:                }
0689:
0690:                return returnValue;
0691:            }
0692:
0693:            static int insertObject(Database db, Object object)
0694:                    throws JPersistException, SQLException,
0695:                    IllegalAccessException, InvocationTargetException,
0696:                    InstantiationException {
0697:                if (logger.isLoggable(Level.FINER))
0698:                    logger.finer("inserting object of class "
0699:                            + object.getClass().getName());
0700:
0701:                if (object == null)
0702:                    throw new JPersistException("object is null");
0703:
0704:                Vector returnValues = new Vector();
0705:
0706:                processClasses(db, object.getClass(), object, true, false,
0707:                        false, false, null, new InsertClassHandler(db,
0708:                                returnValues));
0709:
0710:                if (object instanceof  PersistentObject)
0711:                    ((PersistentObject) object)
0712:                            .setObjectChecksum(calculateChecksum(db, object));
0713:
0714:                int returnValue = 0;
0715:
0716:                for (int i = 0; i < returnValues.size(); i++)
0717:                    returnValue += ((Integer) returnValues.elementAt(i))
0718:                            .intValue();
0719:
0720:                return returnValue;
0721:            }
0722:
0723:            static class InsertClassHandler implements  ClassHandler {
0724:                String identifierQuoteString;
0725:                Vector returnValues;
0726:                Database db;
0727:
0728:                InsertClassHandler(Database db, Vector returnValues)
0729:                        throws JPersistException {
0730:                    this .db = db;
0731:                    this .returnValues = returnValues;
0732:                    this .identifierQuoteString = db.getMetaData()
0733:                            .getIdentifierQuoteString();
0734:                }
0735:
0736:                public void processClass(Class objectClass, Object object,
0737:                        MetaData.Table table, int numberTables,
0738:                        char tableAlias, Map valuesMap, Set selectableColumns)
0739:                        throws JPersistException, SQLException,
0740:                        IllegalAccessException, InvocationTargetException {
0741:                    StringBuffer sqlStatement = new StringBuffer("insert into "
0742:                            + identifierQuoteString + table.getTableName()
0743:                            + identifierQuoteString + " ("), columnsStrBuf = new StringBuffer(), valuesStrBuf = new StringBuffer();
0744:                    Vector columnValues = new Vector(), keysRequested = null, keysReturned = null;
0745:
0746:                    processColumns(table, valuesMap, sqlStatement,
0747:                            columnsStrBuf, valuesStrBuf, columnValues);
0748:
0749:                    String dbUrl = db.getMetaData().getDatabaseUrl()
0750:                            .toLowerCase(), possibleGeneratedKey = table
0751:                            .getPossibleGeneratedKey();
0752:
0753:                    if (dbUrl.startsWith("jdbc:oracle")
0754:                            && possibleGeneratedKey != null) {
0755:                        keysReturned = new Vector();
0756:                        keysReturned.add(possibleGeneratedKey);
0757:                        keysRequested = new Vector(keysReturned);
0758:                    }
0759:
0760:                    returnValues.add(new Integer(db.parameterizedUpdate(
0761:                            sqlStatement.toString(), keysReturned, columnValues
0762:                                    .toArray())));
0763:
0764:                    processGeneratedKeys(table, db.getColumnMapper(), object,
0765:                            dbUrl, keysRequested, keysReturned);
0766:                }
0767:
0768:                void processColumns(MetaData.Table table, Map valuesMap,
0769:                        StringBuffer sqlStatement, StringBuffer columnsStrBuf,
0770:                        StringBuffer valuesStrBuf, Vector columnValues)
0771:                        throws JPersistException {
0772:                    int readOnly = 0;
0773:
0774:                    for (Iterator it = valuesMap.entrySet().iterator(); it
0775:                            .hasNext();) {
0776:                        Map.Entry entry = (Map.Entry) it.next();
0777:                        MetaData.Table.Column column = (MetaData.Table.Column) entry
0778:                                .getKey();
0779:
0780:                        if (!column.isReadOnly()) {
0781:                            Object obj = entry.getValue();
0782:
0783:                            if (!(obj instanceof  NullValue)) {
0784:                                columnsStrBuf
0785:                                        .append((columnsStrBuf.length() > 0 ? ", "
0786:                                                : "")
0787:                                                + identifierQuoteString
0788:                                                + column.getColumnName()
0789:                                                + identifierQuoteString);
0790:                                columnValues.add(obj);
0791:                            }
0792:                        } else
0793:                            readOnly++;
0794:                    }
0795:
0796:                    if (columnValues.size() == 0) {
0797:                        if (readOnly > 0)
0798:                            throw new JPersistException(
0799:                                    "Table "
0800:                                            + table.getTableName()
0801:                                            + " appears to be readonly, might need to log in to the database");
0802:                        else
0803:                            throw new JPersistException(
0804:                                    "There must be some number of column values to insert");
0805:                    }
0806:
0807:                    sqlStatement.append(columnsStrBuf + ") values(");
0808:
0809:                    for (Iterator it = columnValues.iterator(); it.hasNext(); it
0810:                            .next())
0811:                        valuesStrBuf.append((valuesStrBuf.length() > 0 ? ", "
0812:                                : "")
0813:                                + "?");
0814:
0815:                    sqlStatement.append(valuesStrBuf + ")");
0816:                }
0817:
0818:                void processGeneratedKeys(MetaData.Table table,
0819:                        ColumnMapping columnMapper, Object object,
0820:                        String dbUrl, Vector keysRequested, Vector keysReturned)
0821:                        throws JPersistException, IllegalAccessException,
0822:                        InvocationTargetException {
0823:                    if (object instanceof  GeneratedKeys)
0824:                        ((GeneratedKeys) object).setGeneratedKeys(db,
0825:                                keysRequested, keysReturned);
0826:                    else if (dbUrl.startsWith("jdbc:oracle")
0827:                            && keysReturned != null && keysReturned.size() > 0) {
0828:                        if (keysRequested.size() != keysReturned.size())
0829:                            throw new JPersistException(
0830:                                    "Auto-generated keys returned ("
0831:                                            + keysReturned.size()
0832:                                            + ") do not match the number of primary keys requested "
0833:                                            + keysRequested
0834:                                            + "; try implementing GeneratedKeys");
0835:
0836:                        setAutoGeneratedKeys(object, table, columnMapper,
0837:                                keysRequested, keysReturned);
0838:                    } else if (table.getGeneratedKey() != null) {
0839:                        boolean queryExecuted = false;
0840:                        Result result = null;
0841:
0842:                        if (dbUrl.startsWith("jdbc:mysql")) {
0843:                            result = db
0844:                                    .executeQuery("select LAST_INSERT_ID() as id ");
0845:                            queryExecuted = true;
0846:                        } else if (dbUrl.startsWith("jdbc:derby")
0847:                                || dbUrl.startsWith("jdbc:db2")) {
0848:                            result = db
0849:                                    .executeQuery("select IDENTITY_VAL_LOCAL() as id from "
0850:                                            + table.getTableName());
0851:                            queryExecuted = true;
0852:                        } else if (dbUrl.startsWith("jdbc:hsqldb")
0853:                                || dbUrl.startsWith("jdbc:h2")) {
0854:                            result = db
0855:                                    .executeQuery("select IDENTITY() as id from "
0856:                                            + table.getTableName());
0857:                            queryExecuted = true;
0858:                        } else if (dbUrl.startsWith("jdbc:postgresql")) {
0859:                            result = db.executeQuery("select currval('"
0860:                                    + table.getTableName() + '_'
0861:                                    + table.getGeneratedKey() + "_seq"
0862:                                    + "') as id");
0863:                            queryExecuted = true;
0864:                        }
0865:
0866:                        if (queryExecuted && result.hasNext()
0867:                                && result.next() != null) {
0868:                            keysReturned = new Vector();
0869:                            keysReturned.add(result.getColumnValue("id"));
0870:
0871:                            keysRequested = new Vector();
0872:                            keysRequested.add(table.getGeneratedKey());
0873:
0874:                            setAutoGeneratedKeys(object, table, db
0875:                                    .getColumnMapper(), keysRequested,
0876:                                    keysReturned);
0877:                        }
0878:                    }
0879:                }
0880:            }
0881:
0882:            static void setAutoGeneratedKeys(Object object,
0883:                    MetaData.Table table, ColumnMapping columnMapper,
0884:                    Vector keysRequested, Vector keysReturned)
0885:                    throws IllegalAccessException, InvocationTargetException {
0886:                for (int h = 0; h < keysReturned.size(); h++) {
0887:                    String key = (String) keysRequested.elementAt(h);
0888:                    Object value = keysReturned.elementAt(h);
0889:
0890:                    Method method = getMatchingMethod(columnMapper, key,
0891:                            object, false);
0892:
0893:                    if (method != null) {
0894:                        Object convertedObject = ObjectConverter.convertObject(
0895:                                method.getParameterTypes()[0], value);
0896:
0897:                        if (convertedObject != null)
0898:                            method.invoke(object,
0899:                                    new Object[] { convertedObject });
0900:
0901:                        if (object instanceof  PersistentObject)
0902:                            ((PersistentObject) object).getObjectKeyValues()
0903:                                    .put(key, value);
0904:                    }
0905:                }
0906:            }
0907:
0908:            static int updateObject(Database db, Object object,
0909:                    Set nullValuesToInclude, String externalClauses,
0910:                    Object[] parameters) throws JPersistException,
0911:                    SQLException, IllegalAccessException,
0912:                    InvocationTargetException {
0913:                if (logger.isLoggable(Level.FINER))
0914:                    logger.finer("updating object of class "
0915:                            + object.getClass().getName()
0916:                            + "\nexternalClauses = " + externalClauses
0917:                            + "\nparameters[] = "
0918:                            + StringUtils.toString(parameters));
0919:
0920:                if (object == null)
0921:                    throw new JPersistException("object is null");
0922:
0923:                Vector returnValues = new Vector();
0924:                Map updatedKeys = new HashMap();
0925:
0926:                processClasses(db, object.getClass(), object, true, false,
0927:                        false, true, nullValuesToInclude,
0928:                        new UpdateClassHandler(db, updatedKeys, returnValues,
0929:                                externalClauses, parameters));
0930:
0931:                if (object instanceof  PersistentObject) {
0932:                    ((PersistentObject) object).getObjectKeyValues().putAll(
0933:                            updatedKeys);
0934:                    ((PersistentObject) object)
0935:                            .setObjectChecksum(calculateChecksum(db, object));
0936:                }
0937:
0938:                int returnValue = 0;
0939:
0940:                for (int i = 0; i < returnValues.size(); i++)
0941:                    returnValue += ((Integer) returnValues.elementAt(i))
0942:                            .intValue();
0943:
0944:                return returnValue;
0945:            }
0946:
0947:            static class UpdateClassHandler implements  ClassHandler {
0948:                Database db;
0949:                String externalClauses, identifierQuoteString;
0950:                Map updatedKeys;
0951:                Object[] parameters;
0952:                Vector returnValues;
0953:
0954:                UpdateClassHandler(Database db, Map updatedKeys,
0955:                        Vector returnValues, String externalClauses,
0956:                        Object[] parameters) throws JPersistException {
0957:                    this .db = db;
0958:                    this .externalClauses = externalClauses;
0959:                    this .parameters = parameters;
0960:                    this .updatedKeys = updatedKeys;
0961:                    this .returnValues = returnValues;
0962:
0963:                    this .identifierQuoteString = db.getMetaData()
0964:                            .getIdentifierQuoteString();
0965:                }
0966:
0967:                public void processClass(Class objectClass, Object object,
0968:                        MetaData.Table table, int numberTables,
0969:                        char tableAlias, Map valuesMap, Set selectableColumns)
0970:                        throws JPersistException, SQLException,
0971:                        IllegalAccessException, InvocationTargetException {
0972:                    StringBuffer sqlStatement = new StringBuffer();
0973:                    Vector columnValues = new Vector(), whereValues = new Vector();
0974:                    StringBuffer columnsStrBuf = new StringBuffer(), whereStrBuf = new StringBuffer();
0975:
0976:                    for (Iterator it = valuesMap.entrySet().iterator(); it
0977:                            .hasNext();) {
0978:                        Map.Entry entry = (Map.Entry) it.next();
0979:                        MetaData.Table.Column column = (MetaData.Table.Column) entry
0980:                                .getKey();
0981:                        String columnName = column.getColumnName();
0982:                        Object obj = entry.getValue();
0983:
0984:                        if (!column.isReadOnly()) {
0985:                            if (obj instanceof  NullValue)
0986:                                columnsStrBuf
0987:                                        .append((columnsStrBuf.length() > 0 ? ", "
0988:                                                : "")
0989:                                                + identifierQuoteString
0990:                                                + columnName
0991:                                                + identifierQuoteString
0992:                                                + " = null");
0993:                            else {
0994:                                columnsStrBuf
0995:                                        .append((columnsStrBuf.length() > 0 ? ", "
0996:                                                : "")
0997:                                                + identifierQuoteString
0998:                                                + columnName
0999:                                                + identifierQuoteString
1000:                                                + " = ?");
1001:                                columnValues.add(obj);
1002:                            }
1003:                        }
1004:
1005:                        if (object instanceof  PersistentObject
1006:                                && ((PersistentObject) object)
1007:                                        .getObjectKeyValue(columnName) != null)
1008:                            updatedKeys.put(columnName, obj);
1009:
1010:                        if (object instanceof  PersistentObject
1011:                                && (obj = ((PersistentObject) object)
1012:                                        .getObjectKeyValue(columnName)) != null)
1013:                            if (column.isSearchable()) {
1014:                                whereStrBuf
1015:                                        .append((whereStrBuf.length() > 0 ? " and "
1016:                                                : "")
1017:                                                + identifierQuoteString
1018:                                                + columnName
1019:                                                + identifierQuoteString
1020:                                                + (hasWildCards(obj.toString()) ? " like ?"
1021:                                                        : " = ?"));
1022:                                whereValues.add(obj);
1023:                            }
1024:                    }
1025:
1026:                    sqlStatement.append("update " + identifierQuoteString
1027:                            + table.getTableName() + identifierQuoteString
1028:                            + " set " + columnsStrBuf);
1029:
1030:                    if (whereStrBuf.length() > 0
1031:                            && (externalClauses == null || !externalClauses
1032:                                    .startsWith("where")))
1033:                        sqlStatement.append(" where ").append(whereStrBuf);
1034:
1035:                    StringBuffer externalClausesStrBuf = null;
1036:
1037:                    if (externalClauses != null)
1038:                        processExternalClauses(
1039:                                externalClausesStrBuf = new StringBuffer(
1040:                                        externalClauses), table, db
1041:                                        .getColumnMapper(), object,
1042:                                identifierQuoteString);
1043:
1044:                    if (externalClauses != null) {
1045:                        sqlStatement.append(" " + externalClausesStrBuf);
1046:
1047:                        if (parameters != null)
1048:                            for (int i = 0; i < parameters.length; i++)
1049:                                whereValues.add(parameters[i]);
1050:                    }
1051:
1052:                    if (columnValues.size() > 0
1053:                            && (whereValues.size() > 0 || objectClass
1054:                                    .isAnnotationPresent(GlobalUpdate.class))) {
1055:                        columnValues.addAll(whereValues);
1056:                        returnValues.add(new Integer(db
1057:                                .parameterizedUpdate(sqlStatement.toString(),
1058:                                        columnValues.toArray())));
1059:                    } else
1060:                        throw new JPersistException(
1061:                                "Object does not have a where clause and does not extend GlobalUpdate");
1062:                }
1063:            }
1064:
1065:            static int deleteObject(Database db, Object object,
1066:                    Set nullValuesToInclude, String externalClauses,
1067:                    Object[] parameters) throws JPersistException,
1068:                    SQLException, IllegalAccessException,
1069:                    InvocationTargetException {
1070:                if (logger.isLoggable(Level.FINER))
1071:                    logger.finer("deleting object of class "
1072:                            + object.getClass().getName()
1073:                            + "\nexternalClauses = " + externalClauses
1074:                            + "\nparameters[] = "
1075:                            + StringUtils.toString(parameters));
1076:
1077:                if (object == null)
1078:                    throw new JPersistException("object is null");
1079:
1080:                Vector returnValues = new Vector();
1081:
1082:                processClasses(db, object.getClass(), object, true, false,
1083:                        true, false, nullValuesToInclude,
1084:                        new DeleteClassHandler(db, returnValues,
1085:                                externalClauses, parameters));
1086:
1087:                if (object instanceof  PersistentObject)
1088:                    ((PersistentObject) object).makeObjectTransient();
1089:
1090:                int returnValue = 0;
1091:
1092:                for (int i = 0; i < returnValues.size(); i++)
1093:                    returnValue += ((Integer) returnValues.elementAt(i))
1094:                            .intValue();
1095:
1096:                return returnValue;
1097:            }
1098:
1099:            static class DeleteClassHandler implements  ClassHandler {
1100:                Database db;
1101:                String identifierQuoteString, externalClauses;
1102:                Object[] parameters;
1103:                Vector returnValues;
1104:
1105:                DeleteClassHandler(Database db, Vector returnValues,
1106:                        String externalClauses, Object[] parameters)
1107:                        throws JPersistException {
1108:                    this .db = db;
1109:                    this .externalClauses = externalClauses;
1110:                    this .parameters = parameters;
1111:                    this .returnValues = returnValues;
1112:
1113:                    this .identifierQuoteString = db.getMetaData()
1114:                            .getIdentifierQuoteString();
1115:                }
1116:
1117:                public void processClass(Class objectClass, Object object,
1118:                        MetaData.Table table, int numberTables,
1119:                        char tableAlias, Map valuesMap, Set selectableColumns)
1120:                        throws JPersistException, SQLException,
1121:                        IllegalAccessException, InvocationTargetException {
1122:                    StringBuffer sqlStatement = new StringBuffer(), whereStrBuf = new StringBuffer();
1123:                    Vector values = new Vector();
1124:
1125:                    for (Iterator it = valuesMap.entrySet().iterator(); it
1126:                            .hasNext();) {
1127:                        Map.Entry entry = (Map.Entry) it.next();
1128:                        MetaData.Table.Column column = (MetaData.Table.Column) entry
1129:                                .getKey();
1130:
1131:                        if (column.isSearchable()) {
1132:                            String columnName = column.getColumnName();
1133:                            Object obj = entry.getValue();
1134:
1135:                            if (!(obj instanceof  NullValue))
1136:                                if (!(object instanceof  PersistentObject)
1137:                                        || ((PersistentObject) object)
1138:                                                .getObjectChecksum() == 0
1139:                                        || (((PersistentObject) object)
1140:                                                .getObjectChecksum() != 0 && (obj = ((PersistentObject) object)
1141:                                                .getObjectKeyValue(columnName)) != null)) {
1142:                                    whereStrBuf
1143:                                            .append((whereStrBuf.length() > 0 ? " and "
1144:                                                    : "")
1145:                                                    + identifierQuoteString
1146:                                                    + columnName
1147:                                                    + identifierQuoteString
1148:                                                    + (hasWildCards(obj
1149:                                                            .toString()) ? " like ?"
1150:                                                            : " = ?"));
1151:                                    values.add(obj);
1152:                                }
1153:                        }
1154:                    }
1155:
1156:                    sqlStatement.append("delete ");
1157:
1158:                    if (externalClauses == null
1159:                            || !externalClauses.startsWith("from")) {
1160:                        sqlStatement.append(" from " + identifierQuoteString
1161:                                + table.getTableName() + identifierQuoteString);
1162:
1163:                        if (whereStrBuf.length() > 0
1164:                                && (externalClauses == null || !externalClauses
1165:                                        .startsWith("where")))
1166:                            sqlStatement.append(" where ").append(whereStrBuf);
1167:                    }
1168:
1169:                    StringBuffer externalClausesStrBuf = null;
1170:
1171:                    if (externalClauses != null)
1172:                        processExternalClauses(
1173:                                externalClausesStrBuf = new StringBuffer(
1174:                                        externalClauses), table, db
1175:                                        .getColumnMapper(), object,
1176:                                identifierQuoteString);
1177:
1178:                    if (externalClauses != null) {
1179:                        sqlStatement.append(" " + externalClausesStrBuf);
1180:
1181:                        if (parameters != null)
1182:                            for (int i = 0; i < parameters.length; i++)
1183:                                values.add(parameters[i]);
1184:                    }
1185:
1186:                    if (values.size() > 0)
1187:                        returnValues.add(new Integer(db.parameterizedUpdate(
1188:                                sqlStatement.toString(), values.toArray())));
1189:                    else if (!(objectClass
1190:                            .isAnnotationPresent(GlobalDelete.class)))
1191:                        throw new JPersistException(
1192:                                "Object does not have a where clause and does not extend GlobalDelete");
1193:                    else
1194:                        returnValues.add(new Integer(db
1195:                                .executeUpdate(sqlStatement.toString())));
1196:                }
1197:            }
1198:
1199:            static void copyAssociationIds(Database db, Object object,
1200:                    Object associationObject) throws JPersistException,
1201:                    SQLException, IllegalAccessException,
1202:                    InvocationTargetException {
1203:                Set keys = getMatchingImportedExportedKeys(
1204:                        getImportedExportedKeys(db, object, true),
1205:                        getImportedExportedKeys(db, associationObject, false));
1206:
1207:                if (keys.size() != 0) {
1208:                    for (Iterator it = keys.iterator(); it.hasNext();) {
1209:                        MetaData.Table.Key key = (MetaData.Table.Key) it.next();
1210:
1211:                        Method getMethod = getMatchingMethod(db
1212:                                .getColumnMapper(), key.getForeignColumnName(),
1213:                                object, true), setMethod = getMatchingMethod(db
1214:                                .getColumnMapper(), key.getLocalColumnName(),
1215:                                associationObject, false);
1216:
1217:                        if (getMethod == null)
1218:                            throw new JPersistException(
1219:                                    "Could not locate method for column "
1220:                                            + key.getForeignColumnName());
1221:                        if (setMethod == null)
1222:                            throw new JPersistException(
1223:                                    "Could not locate method for column "
1224:                                            + key.getLocalColumnName());
1225:
1226:                        Object convertedObject = ObjectConverter.convertObject(
1227:                                setMethod.getParameterTypes()[0], getMethod
1228:                                        .invoke(object, (Object[]) null));
1229:
1230:                        if (convertedObject == null)
1231:                            throw new JPersistException(
1232:                                    "Could not match primary/foreign keys association relation represented by "
1233:                                            + object.getClass().getName());
1234:
1235:                        setMethod.invoke(associationObject,
1236:                                new Object[] { convertedObject });
1237:                    }
1238:                } else {
1239:                    throw new JPersistException(
1240:                            "The association relation represented by "
1241:                                    + object.getClass().getName()
1242:                                    + " <-- "
1243:                                    + associationObject.getClass().getName()
1244:                                    + " does not have primary/foreign key relationships defined for the underlying"
1245:                                    + " tables (must have a FOREIGN KEY ... REFERENCES ... clause in table creation, see alter table)");
1246:                }
1247:            }
1248:
1249:            static Method getMatchingMethod(ColumnMapping columnMapper,
1250:                    String columnName, Object object, boolean getMethod) {
1251:                Method methods[] = object.getClass().getMethods();
1252:                String matchName = MetaData.normalizeName(columnName);
1253:
1254:                for (int i = 0; i < methods.length; i++)
1255:                    if ((getMethod && methods[i].getName().startsWith("get"))
1256:                            || (!getMethod && methods[i].getName().startsWith(
1257:                                    "set")))
1258:                        if (MetaData.normalizeName(
1259:                                methods[i].getName().substring(3)).indexOf(
1260:                                matchName) > -1)
1261:                            return methods[i];
1262:
1263:                String name = null;
1264:
1265:                if (object instanceof  ColumnMapping
1266:                        && (name = ((ColumnMapping) object)
1267:                                .getTableColumnName(columnName.toLowerCase())) != null)
1268:                    matchName = name;
1269:                else if (columnMapper != null
1270:                        && (name = columnMapper.getTableColumnName(columnName
1271:                                .toLowerCase())) != null)
1272:                    matchName = name;
1273:
1274:                for (int i = 0; i < methods.length; i++)
1275:                    if ((getMethod && methods[i].getName().startsWith("get"))
1276:                            || (!getMethod && methods[i].getName().startsWith(
1277:                                    "set")))
1278:                        if (MetaData.normalizeName(
1279:                                methods[i].getName().substring(3)).indexOf(
1280:                                matchName) > -1)
1281:                            return methods[i];
1282:
1283:                return null;
1284:            }
1285:
1286:            static Set getMatchingImportedExportedKeys(Map objectKeys,
1287:                    Map associationKeys) {
1288:                Set keys = new HashSet();
1289:
1290:                for (Iterator it = associationKeys.entrySet().iterator(); it
1291:                        .hasNext();) {
1292:                    MetaData.Table.Key foreignKey = (MetaData.Table.Key) ((Map.Entry) it
1293:                            .next()).getValue();
1294:
1295:                    if (foreignKey != null) {
1296:                        MetaData.Table.Key localKey = (MetaData.Table.Key) objectKeys
1297:                                .get(foreignKey.getForeignColumnName());
1298:
1299:                        if (localKey != null)
1300:                            keys.add(foreignKey);
1301:                    }
1302:                }
1303:
1304:                return keys;
1305:            }
1306:
1307:            static Map getImportedExportedKeys(Database db, Object object,
1308:                    boolean exportedKeys) throws JPersistException,
1309:                    SQLException {
1310:                Map keys = new HashMap();
1311:                Class objectClass = object.getClass();
1312:                Package p = objectClass.getPackage();
1313:
1314:                while (objectClass != null
1315:                        && p == null
1316:                        || (p != null && (!objectClass.getPackage().equals(
1317:                                ObjectSupport.class.getPackage()) && !objectClass
1318:                                .getPackage().getName().equals("java.lang")))) {
1319:                    String tableName = getTableName(objectClass);
1320:                    MetaData.Table table = db.getMetaData().getTable(
1321:                            db.getConnection(), db.getTableMapper(),
1322:                            db.getColumnMapper(), db.getCatalogPattern(),
1323:                            db.getSchemaPattern(), tableName, object);
1324:
1325:                    if (table == null)
1326:                        throw new JPersistException("Table " + tableName
1327:                                + " is not locatable");
1328:
1329:                    if (exportedKeys)
1330:                        keys.putAll(table.getExportedKeys());
1331:                    else
1332:                        keys.putAll(table.getImportedKeys());
1333:
1334:                    objectClass = objectClass.getSuperclass();
1335:                    p = objectClass.getPackage();
1336:                }
1337:
1338:                return keys;
1339:            }
1340:
1341:            static long calculateChecksum(Database db, Object object)
1342:                    throws JPersistException, SQLException,
1343:                    IllegalAccessException, InvocationTargetException {
1344:                ChecksumCalculator checksumCalculator = new ChecksumCalculator();
1345:
1346:                processClasses(db, object.getClass(), object, true, false,
1347:                        false, false, null, checksumCalculator);
1348:
1349:                return checksumCalculator.getCheckSum();
1350:            }
1351:
1352:            static class ChecksumCalculator implements  ClassHandler {
1353:                CRC32 checkSum = new CRC32();
1354:
1355:                public void processClass(Class objectClass, Object object,
1356:                        MetaData.Table table, int numberTables,
1357:                        char tableAlias, Map valuesMap, Set selectableColumns)
1358:                        throws JPersistException, SQLException,
1359:                        IllegalAccessException, InvocationTargetException {
1360:                    for (Iterator it = valuesMap.entrySet().iterator(); it
1361:                            .hasNext();)
1362:                        checkSum.update(((Map.Entry) it.next()).getValue()
1363:                                .toString().getBytes());
1364:                }
1365:
1366:                long getCheckSum() {
1367:                    return checkSum.getValue();
1368:                }
1369:            }
1370:
1371:            static interface ClassHandler {
1372:                void processClass(Class objectClass, Object object,
1373:                        MetaData.Table table, int numberTables,
1374:                        char tableAlias, Map valuesMap, Set selectableColumns)
1375:                        throws JPersistException, SQLException,
1376:                        IllegalAccessException, InvocationTargetException;
1377:            }
1378:
1379:            static void processClasses(Database db, Class objectClass,
1380:                    Object object, boolean tableRequired,
1381:                    boolean IdColumnsOnly, boolean baseTableOnly,
1382:                    boolean isUpdate, Set nullValuesToInclude, ClassHandler ch)
1383:                    throws JPersistException, SQLException,
1384:                    IllegalAccessException, InvocationTargetException {
1385:                Class headClass = objectClass, baseClass = null;
1386:                Package p = objectClass.getPackage();
1387:                char tableAlias = 'a';
1388:                Vector classes = new Vector();
1389:                boolean singleTable = objectClass
1390:                        .isAnnotationPresent(SingleTableInheritance.class), allFieldsSt = singleTable
1391:                        || objectClass
1392:                                .isAnnotationPresent(ConcreteTableInheritance.class);
1393:                int numberOfTables = 0;
1394:
1395:                while (p == null
1396:                        || (p != null && (!objectClass.getPackage().equals(
1397:                                ObjectSupport.class.getPackage()) && !objectClass
1398:                                .getPackage().getName().equals("java.lang")))) {
1399:                    classes.add(objectClass);
1400:
1401:                    baseClass = objectClass;
1402:                    objectClass = objectClass.getSuperclass();
1403:
1404:                    p = objectClass.getPackage();
1405:                }
1406:
1407:                if (baseTableOnly || allFieldsSt)
1408:                    numberOfTables = 1;
1409:                else
1410:                    numberOfTables = classes.size();
1411:
1412:                for (int i = classes.size() - 1; i > -1; i--, tableAlias++) {
1413:                    String tableName = null;
1414:
1415:                    if (allFieldsSt) {
1416:                        objectClass = headClass;
1417:                        tableName = getTableName(singleTable ? baseClass
1418:                                : headClass);
1419:                    } else {
1420:                        objectClass = (Class) classes.elementAt(i);
1421:                        tableName = getTableName(objectClass);
1422:                    }
1423:
1424:                    MetaData.Table table = db.getMetaData().getTable(
1425:                            db.getConnection(), db.getTableMapper(),
1426:                            db.getColumnMapper(), db.getCatalogPattern(),
1427:                            db.getSchemaPattern(), tableName, object);
1428:
1429:                    if (table == null && tableRequired)
1430:                        throw new JPersistException("Table " + tableName
1431:                                + " is not locatable");
1432:
1433:                    Map valuesMap = new HashMap();
1434:                    Set selectableColumns = new HashSet();
1435:
1436:                    if (table != null)
1437:                        getValuesMap(valuesMap, selectableColumns, table, db
1438:                                .getColumnMapper(), object, objectClass,
1439:                                nullValuesToInclude, IdColumnsOnly, isUpdate,
1440:                                allFieldsSt);
1441:
1442:                    ch.processClass(objectClass, object, table, numberOfTables,
1443:                            tableAlias, valuesMap, selectableColumns);
1444:
1445:                    if (baseTableOnly || allFieldsSt)
1446:                        break;
1447:                }
1448:            }
1449:
1450:            static void getValuesMap(Map valuesMap, Set selectableColumns,
1451:                    MetaData.Table table, ColumnMapping columnMapper,
1452:                    Object object, Class objectClass, Set nullValuesToInclude,
1453:                    boolean IdColumnsOnly, boolean isUpdate,
1454:                    boolean allFieldsSti) throws IllegalAccessException,
1455:                    InvocationTargetException, JPersistException {
1456:                Method methods[] = objectClass.getMethods();
1457:
1458:                for (int i = 0; i < methods.length; i++) {
1459:                    if (methods[i].getName().startsWith("get")
1460:                            && (allFieldsSti || methods[i].getDeclaringClass()
1461:                                    .equals(objectClass))
1462:                            && !methods[i].getName().equals("getDbAssociation")
1463:                            && methods[i].getParameterTypes().length == 0) {
1464:                        MetaData.Table.Column column = null;
1465:                        String methodName = methods[i].getName().substring(3);
1466:                        column = table.getColumn(columnMapper, methodName,
1467:                                object);
1468:
1469:                        if (column != null) {
1470:                            selectableColumns.add(column);
1471:
1472:                            if (object != null) {
1473:                                Object value = methods[i].invoke(object,
1474:                                        (Object[]) null);
1475:
1476:                                if (IdColumnsOnly == false
1477:                                        || table.getPrimaryKeys().size() == 0
1478:                                        || column.isPrimaryKey()) {
1479:                                    if (value != null)
1480:                                        valuesMap.put(column, value);
1481:                                    else {
1482:                                        boolean includeNull = isUpdate
1483:                                                && object != null
1484:                                                && objectClass
1485:                                                        .isAnnotationPresent(UpdateNullValues.class);
1486:
1487:                                        if (!includeNull
1488:                                                && nullValuesToInclude != null)
1489:                                            includeNull = nullValuesToInclude
1490:                                                    .contains(methodName)
1491:                                                    || nullValuesToInclude
1492:                                                            .contains(column
1493:                                                                    .getClassName())
1494:                                                    || nullValuesToInclude
1495:                                                            .contains(Character
1496:                                                                    .toLowerCase(methodName
1497:                                                                            .charAt(0))
1498:                                                                    + methodName
1499:                                                                            .substring(1));
1500:
1501:                                        if (includeNull)
1502:                                            valuesMap.put(column,
1503:                                                    new NullValue(column
1504:                                                            .getDataType()));
1505:                                    }
1506:                                }
1507:                            }
1508:                        }
1509:                    }
1510:                }
1511:            }
1512:
1513:            static void processExternalClauses(
1514:                    StringBuffer externalClausesStrBuf, MetaData.Table table,
1515:                    ColumnMapping columnMapper, Object object,
1516:                    String identifierQuoteString) throws JPersistException {
1517:                int pos = 0;
1518:
1519:                while ((pos = externalClausesStrBuf.indexOf(":")) > -1) {
1520:                    int pos2 = 0;
1521:
1522:                    for (pos2 = pos + 1; pos2 < externalClausesStrBuf.length()
1523:                            && "~`!@#$%^&*()-=+\\|]}[{'\";:/?.>,< "
1524:                                    .indexOf(externalClausesStrBuf.charAt(pos2)) == -1; pos2++)
1525:                        ;
1526:
1527:                    String searchStr = externalClausesStrBuf.substring(pos + 1,
1528:                            pos2), replacement = table.getColumn(columnMapper,
1529:                            searchStr, object).getColumnName();
1530:
1531:                    if (replacement != null)
1532:                        externalClausesStrBuf.replace(pos, pos2,
1533:                                identifierQuoteString + replacement
1534:                                        + identifierQuoteString);
1535:                }
1536:            }
1537:
1538:            static boolean valueIsZeroOrFalse(Object object) {
1539:                if (object instanceof  Integer)
1540:                    return ((Integer) object).intValue() == 0;
1541:
1542:                if (object instanceof  Short)
1543:                    return ((Short) object).shortValue() == 0;
1544:
1545:                if (object instanceof  Long)
1546:                    return ((Long) object).longValue() == 0;
1547:
1548:                if (object instanceof  Float)
1549:                    return ((Float) object).floatValue() == 0.0;
1550:
1551:                if (object instanceof  Double)
1552:                    return ((Double) object).doubleValue() == 0.0;
1553:
1554:                if (object instanceof  Boolean)
1555:                    return ((Boolean) object).booleanValue() == false;
1556:
1557:                return false;
1558:            }
1559:
1560:            static String getTableName(Class objectClass) {
1561:                String tableName = objectClass.getName().replace('$', '.');
1562:
1563:                if (tableName.lastIndexOf('.') != -1)
1564:                    tableName = tableName
1565:                            .substring(tableName.lastIndexOf('.') + 1);
1566:
1567:                if (tableName.indexOf(';') != -1)
1568:                    tableName = tableName.substring(0, tableName.indexOf(';'));
1569:
1570:                return tableName;
1571:            }
1572:
1573:            static boolean hasWildCards(String value) {
1574:                if (value.indexOf('%') != -1 || value.indexOf('_') != -1)
1575:                    return true;
1576:
1577:                return false;
1578:            }
1579:
1580:            static class NullValue {
1581:                int sqlType;
1582:
1583:                NullValue(int sqlType) {
1584:                    this .sqlType = sqlType;
1585:                }
1586:
1587:                public int getSqlType() {
1588:                    return sqlType;
1589:                }
1590:            }
1591:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.