Source Code Cross Referenced for JdbcMetaDataBuilder.java in  » Testing » PolePosition-0.20 » com » versant » core » jdbc » 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 » Testing » PolePosition 0.20 » com.versant.core.jdbc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (c) 1998 - 2005 Versant Corporation
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         * Versant Corporation - initial API and implementation
0010:         */
0011:        package com.versant.core.jdbc;
0012:
0013:        import com.versant.core.common.Debug;
0014:        import com.versant.core.metadata.*;
0015:        import com.versant.core.metadata.parser.*;
0016:        import com.versant.core.jdbc.metadata.*;
0017:        import com.versant.core.jdbc.sql.AutoIncJdbcKeyGenerator;
0018:        import com.versant.core.jdbc.sql.HighLowJdbcKeyGenerator;
0019:        import com.versant.core.jdbc.sql.JdbcNameGenerator;
0020:        import com.versant.core.jdbc.sql.SqlDriver;
0021:        import com.versant.core.util.BeanUtils;
0022:        import com.versant.core.util.StringListParser;
0023:
0024:        import java.sql.Types;
0025:        import java.util.*;
0026:
0027:        import com.versant.core.common.BindingSupportImpl;
0028:        import com.versant.core.common.config.ConfigInfo;
0029:
0030:        /**
0031:         * This builds the meta data for the JdbcStorageManager.
0032:         */
0033:        public class JdbcMetaDataBuilder extends MetaDataBuilder implements 
0034:                JdoExtensionKeys {
0035:
0036:            private final JdbcConfig jdbcConfig;
0037:            private final SqlDriver sqlDriver;
0038:
0039:            private JdbcNameGenerator nameGenerator;
0040:            private JdbcMappingResolver mappingResolver;
0041:
0042:            public final MetaDataEnums MDE = new MetaDataEnums();
0043:            public final JdbcMetaDataEnums jdbcMDE = new JdbcMetaDataEnums();
0044:
0045:            private JdbcKeyGeneratorFactoryRegistry keyGenRegistry;
0046:            private JdbcConverterFactoryRegistry converterRegistry;
0047:            private JdbcClassReferenceGraph jdbcClassReferenceGraph;
0048:
0049:            /**
0050:             * Maps ClassMetaData to ClassInfo.
0051:             */
0052:            private Map classInfoMap = new HashMap();
0053:
0054:            // these are the "fieldnames" used when resolving mappings for these cols
0055:            public static final String DATASTORE_PK_FIELDNAME = "<pk>";
0056:            public static final String CLASS_ID_FIELDNAME = "<class-id>";
0057:            public static final String OPT_LOCK_FIELDNAME = "<opt-lock>";
0058:            public static final String OWNER_REF_FIELDNAME = "<owner>";
0059:            public static final String SEQUENCE_FIELDNAME = "<sequence>";
0060:            public static final String VALUE_FIELDNAME = "<value>";
0061:            public static final String KEY_FIELDNAME = "<key>";
0062:
0063:            // these are the names of the built in key generators
0064:            public static final String KEYGEN_HIGHLOW = "HIGHLOW";
0065:            public static final String KEYGEN_AUTOINC = "AUTOINC";
0066:
0067:            /**
0068:             * These hold tempory info we need to track for a class during meta data
0069:             * generation. Each class for our store is associated with one of these
0070:             * through the classInfoMap.
0071:             */
0072:            public static class ClassInfo {
0073:
0074:                public ClassMetaData cmd;
0075:
0076:                public ArrayList elements;
0077:                public JdbcKeyGeneratorFactory keyGenFactory;
0078:                public Object keyGenFactoryArgs;
0079:                public String pkConstraintName;
0080:                public JdoExtension optimisticLockingExt;
0081:                public String pkFkConstraintName;
0082:                public JdbcConstraint pkFkConstraint;
0083:                public ArrayList indexExts = new ArrayList();
0084:                public ArrayList autoIndexes = new ArrayList(); // of JdbcIndex
0085:                public JdoExtension inheritance;
0086:                public JdoExtension classIdExt;
0087:                public boolean noClassIdCol;
0088:                private Set createdAfterClient;
0089:
0090:                public Set getCreatedAfterClient() {
0091:                    if (createdAfterClient == null) {
0092:                        createdAfterClient = new HashSet();
0093:                    }
0094:                    return createdAfterClient;
0095:                }
0096:            }
0097:
0098:            /**
0099:             * The jdbcDriver parameter may be null if this is not available.
0100:             */
0101:            public JdbcMetaDataBuilder(ConfigInfo config,
0102:                    JdbcConfig jdbcConfig, ClassLoader loader,
0103:                    SqlDriver sqlDriver, boolean quiet) {
0104:                super (config, loader, quiet);
0105:                this .jdbcConfig = jdbcConfig;
0106:                this .sqlDriver = sqlDriver;
0107:            }
0108:
0109:            protected FetchGroupBuilder createFetchGroupBuilder() {
0110:                return new JdbcFetchGroupBuilder(jmd);
0111:            }
0112:
0113:            public boolean isCdRefsInDefaultFetchGroup() {
0114:                return jdbcConfig.oidsInDefaultFetchGroup;
0115:            }
0116:
0117:            public int getCdCacheStrategy() {
0118:                return jdbcConfig.cacheStrategy;
0119:            }
0120:
0121:            public ModelMetaData buildMetaData(JdoRoot[] roots) {
0122:                keyGenRegistry = new JdbcKeyGeneratorFactoryRegistry(loader);
0123:                keyGenRegistry.add(KEYGEN_HIGHLOW, keyGenRegistry
0124:                        .getFactory(HighLowJdbcKeyGenerator.Factory.class
0125:                                .getName()));
0126:                keyGenRegistry.add(KEYGEN_AUTOINC, keyGenRegistry
0127:                        .getFactory(AutoIncJdbcKeyGenerator.Factory.class
0128:                                .getName()));
0129:                converterRegistry = new JdbcConverterFactoryRegistry(loader);
0130:
0131:                mappingResolver = new JdbcMappingResolver();
0132:                mappingResolver.init(sqlDriver, parseTypeMappings(),
0133:                        parseJavaTypeMappings());
0134:                mappingResolver.registerStoreTypes(mdutils);
0135:
0136:                if (jdbcConfig.jdbcKeyGenerator == null) {
0137:                    jdbcConfig.jdbcKeyGenerator = JdbcMetaDataBuilder.KEYGEN_HIGHLOW;
0138:                }
0139:                if (jdbcConfig.jdbcKeyGeneratorProps == null) {
0140:
0141:                    jdbcConfig.jdbcKeyGeneratorProps = Collections.EMPTY_MAP;
0142:
0143:                }
0144:
0145:                if (jdbcConfig.jdbcNameGenerator != null) {
0146:                    nameGenerator = (JdbcNameGenerator) BeanUtils.newInstance(
0147:                            jdbcConfig.jdbcNameGenerator, loader,
0148:                            JdbcNameGenerator.class);
0149:                } else {
0150:                    nameGenerator = sqlDriver.createJdbcNameGenerator();
0151:                }
0152:                BeanUtils.setProperties(nameGenerator,
0153:                        jdbcConfig.jdbcNameGeneratorProps);
0154:                jmd.jdbcMetaData = new JdbcMetaData(jmd, jdbcConfig);
0155:
0156:                return super .buildMetaData(roots);
0157:            }
0158:
0159:            protected void doHorizontal(ClassMetaData[] ca) {
0160:                //create all the fake field for horizontal instances
0161:                for (int j = 0; j < ca.length; j++) {
0162:                    ClassMetaData cmd = ca[j];
0163:                    try {
0164:                        createHorizontalFieldMetaData(cmd, quiet);
0165:                    } catch (RuntimeException e) {
0166:                        cmd.addError(e, quiet);
0167:                    }
0168:                }
0169:            }
0170:
0171:            protected void doEmbedded(ClassMetaData[] ca) {
0172:                //create all the fake field for embedded instances
0173:                for (int j = 0; j < ca.length; j++) {
0174:                    ClassMetaData cmd = ca[j];
0175:                    try {
0176:                        createEmbeddeFieldMetaData(cmd, quiet);
0177:                    } catch (RuntimeException e) {
0178:                        cmd.addError(e, quiet);
0179:                    }
0180:                }
0181:            }
0182:
0183:            protected void checkForHorizontal(JdoClass jdoCls, ClassMetaData cmd) {
0184:                if (jdoCls.getInheritance(jdbcMDE.INHERITANCE_ENUM) == JdbcClass.INHERITANCE_HORIZONTAL) {
0185:                    cmd.horizontal = true;
0186:                }
0187:            }
0188:
0189:            public JdbcConfig getJdbcConfig() {
0190:                return jdbcConfig;
0191:            }
0192:
0193:            public JdbcNameGenerator getNameGenerator() {
0194:                return nameGenerator;
0195:            }
0196:
0197:            /**
0198:             * Get the ClassInfo for cmd.
0199:             */
0200:            public ClassInfo getClassInfo(ClassMetaData cmd) {
0201:                return (ClassInfo) classInfoMap.get(cmd);
0202:            }
0203:
0204:            /**
0205:             * Get the elements field of the ClassInfo for cmd.
0206:             */
0207:            private ArrayList getClassElements(ClassMetaData cmd) {
0208:                return getClassInfo(cmd).elements;
0209:            }
0210:
0211:            protected void preBuildFetchGroupsHook() {
0212:                ClassMetaData[] classes = jmd.classes;
0213:                int clen = classes.length;
0214:
0215:                // find all classes that belong to us and do whatever we can without
0216:                // having all the JdbcClass objects and tables yet
0217:                if (Debug.DEBUG) {
0218:                    Debug.OUT
0219:                            .println("MDB-JDBC: Creating JdbcClass objects ... ");
0220:                }
0221:                for (int i = 0; i < clen; i++) {
0222:                    ClassMetaData cmd = classes[i];
0223:                    if (cmd.pcSuperMetaData != null) {
0224:                        continue;
0225:                    }
0226:                    try {
0227:                        createJdbcClass(cmd, quiet);
0228:                    } catch (RuntimeException e) {
0229:                        cmd.addError(e, quiet);
0230:                    }
0231:                }
0232:
0233:                // Make sure that all classes have tables and table names. This is
0234:                // done starting at the base classes and recursively processing
0235:                // subclasses.
0236:                if (Debug.DEBUG) {
0237:                    Debug.OUT
0238:                            .println("MDB-JDBC: Creating JdbcTable objects ... ");
0239:                }
0240:                for (int i = 0; i < clen; i++) {
0241:                    ClassMetaData cmd = classes[i];
0242:                    try {
0243:                        processBaseClassTable(cmd);
0244:                    } catch (RuntimeException e) {
0245:                        cmd.addError(e, quiet);
0246:                    }
0247:
0248:                }
0249:
0250:                // find the primary keys (datastore or application) for all classes
0251:                // and make sure the pk columns have names
0252:                if (Debug.DEBUG) {
0253:                    Debug.OUT
0254:                            .println("MDB-JDBC: Finding and naming primary keys ... ");
0255:                }
0256:                for (int i = 0; i < clen; i++) {
0257:                    ClassMetaData cmd = classes[i];
0258:                    if (cmd.pcSuperMetaData != null)
0259:                        continue;
0260:                    try {
0261:                        processPrimaryKey(cmd, quiet);
0262:                    } catch (RuntimeException e) {
0263:                        cmd.addError(e, quiet);
0264:                    }
0265:                }
0266:
0267:                // create descriminator columns and figure out values
0268:                if (Debug.DEBUG) {
0269:                    Debug.OUT
0270:                            .println("MDB-JDBC: Creating descriminator columns ... ");
0271:                }
0272:                for (int i = 0; i < clen; i++) {
0273:                    ClassMetaData cmd = classes[i];
0274:                    if (cmd.pcSuperMetaData != null) {
0275:                        continue;
0276:                    }
0277:                    try {
0278:                        processClassIdCol(cmd, quiet, new HashMap());
0279:                    } catch (RuntimeException e) {
0280:                        cmd.addError(e, quiet);
0281:                    }
0282:                }
0283:
0284:                // processing the persist after extensions
0285:                for (int j = 0; j < clen; j++) {
0286:                    ClassMetaData cmd = classes[j];
0287:                    ClassInfo cInfo = getClassInfo(cmd.top);
0288:                    cInfo.getCreatedAfterClient().clear();
0289:                    JdoElement[] elements = cmd.jdoClass.elements;
0290:                    int n = elements.length;
0291:                    for (int i = 0; i < n; i++) {
0292:                        JdoElement o = elements[i];
0293:                        if (o instanceof  JdoExtension) {
0294:                            JdoExtension e = (JdoExtension) o;
0295:                            if (e.key == PERSIST_AFTER) {
0296:                                if (e.nested == null)
0297:                                    continue;
0298:                                for (int k = 0; k < e.nested.length; k++) {
0299:                                    JdoExtension jdoExtension = e.nested[k];
0300:                                    if (jdoExtension != null) {
0301:                                        cInfo
0302:                                                .getCreatedAfterClient()
0303:                                                .add(
0304:                                                        jmd
0305:                                                                .getClassMetaData(jdoExtension.value).top);
0306:                                    }
0307:                                }
0308:                            }
0309:                        }
0310:                    }
0311:                }
0312:
0313:                // calc maxPkSimpleColumns and set datastoreIdentityType
0314:                if (Debug.DEBUG) {
0315:                    Debug.OUT
0316:                            .println("MDB-JDBC: Calculating maxPkSimpleColumns ... ");
0317:                }
0318:                int maxPkSimpleColumns = 0;
0319:                for (int i = 0; i < clen; i++) {
0320:                    ClassMetaData cmd = classes[i];
0321:                    try {
0322:                        if (cmd.horizontal)
0323:                            continue;
0324:                        JdbcClass jdbcClass = ((JdbcClass) cmd.storeClass);
0325:                        int n = jdbcClass.table.pkSimpleColumnCount;
0326:                        if (n > maxPkSimpleColumns) {
0327:                            maxPkSimpleColumns = n;
0328:                        }
0329:                        cmd.datastoreIdentityTypeCode = jdbcClass.table.pk[0].javaTypeCode;
0330:                        cmd.datastoreIdentityType = jdbcClass.table.pk[0].javaType;
0331:                    } catch (RuntimeException e) {
0332:                        cmd.addError(e, quiet);
0333:                    }
0334:                }
0335:                ((JdbcMetaData) jmd.jdbcMetaData).maxPkSimpleColumns = maxPkSimpleColumns;
0336:
0337:                // complete optimistic locking - this is done now so that use visible
0338:                // fields can be used for rowversion and timestamp locking
0339:                if (Debug.DEBUG) {
0340:                    Debug.OUT
0341:                            .println("MDB-JDBC: Completing optimistic locking ... ");
0342:                }
0343:                for (int i = 0; i < clen; i++) {
0344:                    ClassMetaData cmd = classes[i];
0345:                    if (cmd.pcSuperMetaData != null)
0346:                        continue;
0347:                    try {
0348:                        completeOptimisticLocking(cmd, quiet);
0349:                    } catch (RuntimeException e) {
0350:                        cmd.addError(e, quiet);
0351:                    }
0352:                }
0353:
0354:                // complete REF fields now that we have all the classes
0355:                // and primary keys
0356:                if (Debug.DEBUG) {
0357:                    Debug.OUT.println("MDB-JDBC: Creating REF fields ... ");
0358:                }
0359:                for (int i = 0; i < clen; i++) {
0360:                    ClassMetaData cmd = classes[i];
0361:                    try {
0362:                        processRefAndPolyRefFields(cmd, quiet);
0363:                    } catch (RuntimeException e) {
0364:                        cmd.addError(e, quiet);
0365:                    }
0366:                }
0367:
0368:                // complete COLLECTION fields now that we have all the classes
0369:                // and primary keys and refs
0370:                if (Debug.DEBUG) {
0371:                    Debug.OUT
0372:                            .println("MDB-JDBC: Creating COLLECTION fields ... ");
0373:                }
0374:                for (int i = 0; i < clen; i++) {
0375:                    ClassMetaData cmd = classes[i];
0376:                    try {
0377:                        if (cmd.horizontal)
0378:                            continue;
0379:                        processCollectionFields(cmd, quiet);
0380:                    } catch (RuntimeException e) {
0381:                        cmd.addError(e, quiet);
0382:                    }
0383:                }
0384:
0385:                // create the cols arrays on all class tables, name all field columns
0386:                // without names and sanity check columns and add any extra fake
0387:                // fields to the fields array on ClassMetaData
0388:                if (Debug.DEBUG) {
0389:                    Debug.OUT
0390:                            .println("MDB-JDBC: Finalizing table column arrays and fake fields ... ");
0391:                }
0392:                for (int i = 0; i < clen; i++) {
0393:                    ClassMetaData cmd = classes[i];
0394:                    //            if (cmd.horizontal) continue;
0395:                    if (cmd.pcSuperMetaData != null)
0396:                        continue;
0397:                    try {
0398:                        finalizeFakesAndTableColumns(cmd);
0399:                    } catch (RuntimeException e) {
0400:                        cmd.addError(e, quiet);
0401:                    }
0402:                }
0403:
0404:                jdbcClassReferenceGraph = new JdbcClassReferenceGraph(
0405:                        jmd.classes);
0406:                jdbcClassReferenceGraph.sort();
0407:
0408:                if (Debug.DEBUG) {
0409:                    Debug.OUT.println("MDB-JDBC: Creating constraints ... ");
0410:                }
0411:                for (int i = 0; i < clen; i++) {
0412:                    ClassMetaData cmd = classes[i];
0413:                    try {
0414:                        doConstraints(cmd);
0415:                    } catch (RuntimeException e) {
0416:                        cmd.addError(e, quiet);
0417:                    }
0418:                }
0419:
0420:                //release resources that was used for sorting
0421:                jdbcClassReferenceGraph.releaseMem();
0422:
0423:                // build the fields array on JdbcClass for each class
0424:                if (Debug.DEBUG) {
0425:                    Debug.OUT
0426:                            .println("MDB-JDBC: Finalizing fields arrays ... ");
0427:                }
0428:                for (int i = 0; i < clen; i++) {
0429:                    ClassMetaData cmd = classes[i];
0430:                    FieldMetaData[] fa = cmd.fields;
0431:                    if (fa == null)
0432:                        continue;
0433:                    JdbcField[] a = ((JdbcClass) cmd.storeClass).fields = new JdbcField[fa.length];
0434:                    for (int j = fa.length - 1; j >= 0; j--) {
0435:                        FieldMetaData fmd = fa[j];
0436:                        fmd.fieldNo = j; // need to do this in case of fake fields
0437:                        JdbcField jdbcField = (JdbcField) fmd.storeField;
0438:                        a[j] = jdbcField;
0439:                        if (jdbcField != null)
0440:                            jdbcField.initMainTableCols();
0441:                    }
0442:                }
0443:
0444:                // figure out which columns should be marked as shared
0445:                if (Debug.DEBUG) {
0446:                    Debug.OUT.println("MDB-JDBC: Choosing shared columns ... ");
0447:                }
0448:                SharedColumnChooser sharedColumnChooser = new SharedColumnChooser();
0449:                for (int i = 0; i < clen; i++) {
0450:                    ClassMetaData cmd = classes[i];
0451:                    if (cmd.pcSuperMetaData != null)
0452:                        continue;
0453:                    if (cmd.horizontal)
0454:                        continue;
0455:                    try {
0456:                        sharedColumnChooser.chooseSharedColumns(cmd);
0457:                    } catch (RuntimeException e) {
0458:                        cmd.addError(e, quiet);
0459:                    }
0460:                }
0461:
0462:                // build the fields array on JdbcClass for each class
0463:                if (Debug.DEBUG) {
0464:                    Debug.OUT
0465:                            .println("MDB-JDBC: Finalizing for update columns for fields ... ");
0466:                }
0467:                for (int i = 0; i < clen; i++) {
0468:                    ClassMetaData cmd = classes[i];
0469:                    JdbcField[] fields = ((JdbcClass) cmd.storeClass).fields;
0470:                    if (fields == null)
0471:                        continue;
0472:                    for (int j = fields.length - 1; j >= 0; j--) {
0473:                        JdbcField f = fields[j];
0474:                        if (f != null)
0475:                            f.initMainTableColsForUpdate();
0476:                    }
0477:                }
0478:
0479:                // copy optimistic locking settings down each heirachy
0480:                if (Debug.DEBUG) {
0481:                    Debug.OUT
0482:                            .println("MDB-JDBC: Copying optimistic locking down heirachies ... ");
0483:                }
0484:                for (int i = 0; i < clen; i++) {
0485:                    ClassMetaData cmd = classes[i];
0486:                    ((JdbcClass) cmd.storeClass).copyOptimisticLockingToSubs();
0487:                }
0488:
0489:                // finalize constraints
0490:                if (Debug.DEBUG) {
0491:                    Debug.OUT
0492:                            .println("MDB-JDBC: Finalizing table constraints ... ");
0493:                }
0494:                for (int i = 0; i < clen; i++) {
0495:                    ClassMetaData cmd = classes[i];
0496:                    try {
0497:                        finalizeConstraints(cmd);
0498:                    } catch (RuntimeException e) {
0499:                        cmd.addError(e, quiet);
0500:                    }
0501:                }
0502:                ArrayList tables = ((JdbcMetaData) jmd.jdbcMetaData)
0503:                        .getTables(true);
0504:                int size = tables.size();
0505:                for (int i = 0; i < size; i++) {
0506:                    JdbcTable jdbcTable = (JdbcTable) tables.get(i);
0507:                    jdbcTable.nameConstraints(nameGenerator);
0508:                }
0509:                for (int i = 0; i < clen; i++) {
0510:                    ClassMetaData cmd = classes[i];
0511:                    try {
0512:                        finalizeConstraints(cmd);
0513:                    } catch (RuntimeException e) {
0514:                        cmd.addError(e, quiet);
0515:                    }
0516:                }
0517:
0518:                // find index extensions and create them
0519:                if (Debug.DEBUG) {
0520:                    Debug.OUT
0521:                            .println("MDB-JDBC: Processing index extensions ... ");
0522:                }
0523:                for (int i = 0; i < clen; i++) {
0524:                    ClassMetaData cmd = classes[i];
0525:                    if (cmd.pcSuperMetaData != null)
0526:                        continue;
0527:                    try {
0528:                        createMainTableIndexes(cmd, quiet);
0529:                    } catch (RuntimeException e) {
0530:                        cmd.addError(e, quiet);
0531:                    }
0532:                }
0533:
0534:                // make sure link table indexes are named
0535:                if (Debug.DEBUG) {
0536:                    Debug.OUT
0537:                            .println("MDB-JDBC: Naming link table indexes ...");
0538:                }
0539:                for (int i = 0; i < clen; i++) {
0540:                    ClassMetaData cmd = classes[i];
0541:                    FieldMetaData[] fields = cmd.fields;
0542:                    if (fields == null)
0543:                        continue;
0544:                    for (int j = 0; j < fields.length; j++) {
0545:                        JdbcField jf = (JdbcField) fields[j].storeField;
0546:                        if (jf != null) {
0547:                            try {
0548:                                jf.nameLinkTableIndexes(nameGenerator);
0549:                            } catch (RuntimeException e) {
0550:                                cmd.addError(e, quiet);
0551:                            }
0552:                        }
0553:                    }
0554:                }
0555:
0556:                // create key generator instances
0557:                if (Debug.DEBUG) {
0558:                    Debug.OUT.println("MDB-JDBC: Creating key generators ... ");
0559:                }
0560:                createKeyGenerators(quiet);
0561:            }
0562:
0563:            /**
0564:             * Create main table indexes for cmd and recursively all of its subclasses.
0565:             * This is a NOP if cmd is not a base class. This also make sure that all
0566:             * of the indexes have names and gets rid of duplicate indexes (only
0567:             * the first one is kept).
0568:             */
0569:            private void createMainTableIndexes(ClassMetaData cmd, boolean quiet) {
0570:                if (cmd.pcSuperMetaData != null)
0571:                    return;
0572:
0573:                ArrayList all = new ArrayList();
0574:                collectIndexes(cmd, all, quiet);
0575:                ArrayList auto = new ArrayList();
0576:                collectAutoIndexes(cmd, auto);
0577:
0578:                // get rid of auto indexes that have same columns as manual indexes
0579:                // or other auto indexes
0580:                HashSet s = new HashSet();
0581:                s.addAll(all);
0582:                for (Iterator i = auto.iterator(); i.hasNext();) {
0583:                    Object o = i.next();
0584:                    if (s.contains(o)) {
0585:                        i.remove();
0586:                    } else {
0587:                        s.add(o);
0588:                    }
0589:                }
0590:                all.addAll(auto);
0591:
0592:                Map tablesToIndexs = new HashMap();
0593:                for (int i = 0; i < all.size(); i++) {
0594:                    JdbcIndex index = (JdbcIndex) all.get(i);
0595:                    JdbcTable table = null;
0596:                    boolean ignore = false;
0597:                    if (index.cols.length > 0) {
0598:                        table = index.cols[0].table;
0599:                        ignore = false;
0600:                        for (int j = 1; j < index.cols.length; j++) {
0601:                            JdbcColumn col = index.cols[j];
0602:                            if (col.table != table) {
0603:                                System.out
0604:                                        .println("\n\n WARNING: This composite index contains colums from "
0605:                                                + "2 different tables. Ignoring it");
0606:                                ignore = true;
0607:                            }
0608:                        }
0609:                    }
0610:                    if (ignore)
0611:                        continue;
0612:
0613:                    Set indexs = (Set) tablesToIndexs.get(table);
0614:                    if (indexs == null) {
0615:                        indexs = new HashSet();
0616:                        tablesToIndexs.put(table, indexs);
0617:                    }
0618:                    indexs.add(index);
0619:                }
0620:
0621:                for (Iterator iterator = tablesToIndexs.entrySet().iterator(); iterator
0622:                        .hasNext();) {
0623:                    Map.Entry mapEntry = (Map.Entry) iterator.next();
0624:                    JdbcTable table = (JdbcTable) mapEntry.getKey();
0625:                    if (table != null) {
0626:                        Set indexs = (Set) mapEntry.getValue();
0627:                        JdbcIndex[] a = new JdbcIndex[indexs.size()];
0628:                        indexs.toArray(a);
0629:                        table.indexes = a;
0630:                        for (int i = 0; i < a.length; i++) {
0631:                            if (a[i] != null && a[i].name == null) {
0632:                                generateNameForIndex(nameGenerator, table.name,
0633:                                        a[i]);
0634:                            }
0635:                        }
0636:                    }
0637:                }
0638:            }
0639:
0640:            protected void postAllFieldsCreatedHook() {
0641:                ClassMetaData[] ca = jmd.classes;
0642:
0643:                // fill the stateFieldNo on each JdbcField
0644:                for (int i = ca.length - 1; i >= 0; i--) {
0645:                    ClassMetaData cmd = ca[i];
0646:                    JdbcClass jc = (JdbcClass) cmd.storeClass;
0647:                    if (jc == null || jc.fields == null)
0648:                        continue;
0649:                    for (int j = jc.fields.length - 1; j >= 0; j--) {
0650:                        JdbcField f = jc.fields[j];
0651:                        if (f == null) {
0652:                            continue;
0653:                        }
0654:                        f.stateFieldNo = f.fmd.fieldNo + cmd.super FieldCount;
0655:                    }
0656:                }
0657:
0658:                // fill the stateFields array on each JdbcClass
0659:                for (int i = ca.length - 1; i >= 0; i--) {
0660:                    ClassMetaData cmd = ca[i];
0661:                    JdbcClass jc = (JdbcClass) cmd.storeClass;
0662:                    if (jc == null)
0663:                        continue;
0664:                    jc.buildStateFields();
0665:                }
0666:                fillFGMetaData();
0667:            }
0668:
0669:            private void collectIndexes(ClassMetaData cmd, ArrayList indexes,
0670:                    boolean quiet) {
0671:                ArrayList indexExts = getClassInfo(cmd).indexExts;
0672:                for (int j = 0; j < indexExts.size(); j++) {
0673:                    try {
0674:                        indexes.add(processIndexExtension(cmd,
0675:                                (JdoExtension) indexExts.get(j), quiet));
0676:                    } catch (RuntimeException e) {
0677:                        cmd.addError(e, quiet);
0678:                    }
0679:                }
0680:                ClassMetaData[] subs = cmd.pcSubclasses;
0681:                if (subs != null) {
0682:                    for (int i = 0; i < subs.length; i++) {
0683:                        try {
0684:                            collectIndexes(subs[i], indexes, quiet);
0685:                        } catch (RuntimeException e) {
0686:                            cmd.addError(e, quiet);
0687:                        }
0688:                    }
0689:                }
0690:            }
0691:
0692:            private void collectAutoIndexes(ClassMetaData cmd, ArrayList indexes) {
0693:                indexes.addAll(getClassInfo(cmd).autoIndexes);
0694:                ClassMetaData[] subs = cmd.pcSubclasses;
0695:                if (subs != null) {
0696:                    for (int i = 0; i < subs.length; i++) {
0697:                        collectAutoIndexes(subs[i], indexes);
0698:                    }
0699:                }
0700:            }
0701:
0702:            /**
0703:             * Generate the name for an index. The columns in the index must have
0704:             * names.
0705:             */
0706:            public static void generateNameForIndex(JdbcNameGenerator namegen,
0707:                    String tableName, JdbcIndex idx) {
0708:                int n = idx.cols.length;
0709:                String[] cn = new String[n];
0710:                for (int i = 0; i < n; i++)
0711:                    cn[i] = idx.cols[i].name;
0712:                idx.name = namegen.generateIndexName(tableName, cn);
0713:            }
0714:
0715:            /**
0716:             * Convert the type mapping strings for s into JdbcTypeMapping instances.
0717:             */
0718:            private ArrayList parseTypeMappings() {
0719:                String sdb = sqlDriver.getName();
0720:                ArrayList in = jdbcConfig.typeMappings;
0721:                int n = in.size();
0722:                ArrayList a = new ArrayList(n);
0723:                StringListParser p = new StringListParser();
0724:                for (int i = 0; i < n; i++) {
0725:                    String s = (String) in.get(i);
0726:                    p.setString(s);
0727:                    JdbcTypeMapping m = new JdbcTypeMapping();
0728:                    m.parse(p, converterRegistry);
0729:                    String mdb = m.getDatabase();
0730:                    if (mdb == null || mdb.equals(sdb))
0731:                        a.add(m);
0732:                }
0733:                return a;
0734:            }
0735:
0736:            /**
0737:             * Convert the java type mapping strings for s into JdbcJavaTypeMapping
0738:             * instances.
0739:             */
0740:            private ArrayList parseJavaTypeMappings() {
0741:                String sdb = sqlDriver.getName();
0742:                ArrayList in = jdbcConfig.javaTypeMappings;
0743:                int n = in.size();
0744:                ArrayList a = new ArrayList(n);
0745:                StringListParser p = new StringListParser();
0746:                for (int i = 0; i < n; i++) {
0747:                    String s = (String) in.get(i);
0748:                    p.setString(s);
0749:                    JdbcJavaTypeMapping m = new JdbcJavaTypeMapping();
0750:                    m.parse(p, converterRegistry);
0751:                    String mdb = m.getDatabase();
0752:                    if (mdb == null || mdb.equals(sdb))
0753:                        a.add(m);
0754:                }
0755:                return a;
0756:            }
0757:
0758:            /**
0759:             * Process an index extension for cmd. This will resolve the names of
0760:             * all fields in the index to their column names and register the name
0761:             * of the index if one has been specified. The index is returned.
0762:             */
0763:            private JdbcIndex processIndexExtension(ClassMetaData cmd,
0764:                    JdoExtension e, boolean quiet) {
0765:                JdbcIndex idx = new JdbcIndex();
0766:                idx.name = e.value;
0767:                ArrayList cols = new ArrayList();
0768:                JdoExtension[] a = e.nested;
0769:                int n = a == null ? 0 : a.length;
0770:                for (int i = 0; i < n; i++) {
0771:                    JdoExtension ne = a[i];
0772:                    switch (ne.key) {
0773:                    case JDBC_CLUSTERED:
0774:                        try {
0775:                            idx.clustered = ne.getBoolean();
0776:                        } catch (RuntimeException x) {
0777:                            cmd.addError(x, quiet);
0778:                        }
0779:                        break;
0780:                    case JDBC_UNIQUE:
0781:                        try {
0782:                            idx.unique = ne.getBoolean();
0783:                        } catch (RuntimeException x) {
0784:                            cmd.addError(x, quiet);
0785:                        }
0786:                        break;
0787:                    case FIELD_NAME:
0788:                        JdbcColumn[] mtc;
0789:                        String fname = ne.getString();
0790:                        if (fname.equals(DATASTORE_PK_FIELDNAME)) {
0791:                            mtc = ((JdbcClass) cmd.storeClass).table.pk;
0792:                        } else {
0793:                            FieldMetaData fmd = cmd.getFieldMetaData(fname);
0794:                            if (fmd == null) {
0795:                                RuntimeException x = BindingSupportImpl
0796:                                        .getInstance().runtime(
0797:                                                "Field '" + ne.value
0798:                                                        + "' not found\n"
0799:                                                        + ne.getContext());
0800:                                cmd.addError(x, quiet);
0801:                            }
0802:                            JdbcField jf = (JdbcField) fmd.storeField;
0803:                            if (jf == null || jf.mainTableCols == null) {
0804:                                RuntimeException x = BindingSupportImpl
0805:                                        .getInstance()
0806:                                        .runtime(
0807:                                                "Field '"
0808:                                                        + ne.value
0809:                                                        + "' is not stored in the main table\n"
0810:                                                        + ne.getContext());
0811:                                fmd.addError(x, quiet);
0812:                            }
0813:                            mtc = jf.mainTableCols;
0814:                        }
0815:                        for (int j = 0; j < mtc.length; j++)
0816:                            cols.add(mtc[j]);
0817:                        break;
0818:                    default:
0819:                        MetaDataBuilder.throwUnexpectedExtension(ne);
0820:                    }
0821:                }
0822:                n = cols.size();
0823:                if (n == 0) {
0824:                    RuntimeException x = BindingSupportImpl.getInstance()
0825:                            .runtime(
0826:                                    "Index does not include any fields\n"
0827:                                            + e.getContext());
0828:                    cmd.addError(x, quiet);
0829:                    return null;
0830:                }
0831:                JdbcColumn[] idxCols = new JdbcColumn[n];
0832:                cols.toArray(idxCols);
0833:                idx.setCols(idxCols);
0834:                if (idx.name != null) {
0835:                    JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
0836:                    try {
0837:                        nameGenerator.addIndexName(jdbcClass.table.name,
0838:                                idx.name);
0839:                    } catch (IllegalArgumentException x) {
0840:                        RuntimeException ex = BindingSupportImpl.getInstance()
0841:                                .runtime(x.getMessage(), x);
0842:                        cmd.addError(ex, quiet);
0843:                    }
0844:                }
0845:                return idx;
0846:            }
0847:
0848:            private void fillFGMetaData() {
0849:                ClassMetaData[] classes = jmd.classes;
0850:                int clen = classes.length;
0851:                if (Debug.DEBUG) {
0852:                    Debug.OUT
0853:                            .println("MDB-JDBC: Filling fetch group meta data ... ");
0854:                }
0855:                for (int i = 0; i < clen; i++) {
0856:                    ClassMetaData cmd = classes[i];
0857:                    processFetchGroups(cmd);
0858:                }
0859:            }
0860:
0861:            /**
0862:             * Finish up optimistic locking for cmd.
0863:             */
0864:            private void completeOptimisticLocking(ClassMetaData cmd,
0865:                    boolean quiet) {
0866:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
0867:                ClassInfo info = getClassInfo(cmd);
0868:                switch (jdbcClass.optimisticLocking) {
0869:                case JdbcClass.OPTIMISTIC_LOCKING_VERSION:
0870:                case JdbcClass.OPTIMISTIC_LOCKING_TIMESTAMP:
0871:                    processTimestampOrRowVersionLocking(jdbcClass, cmd,
0872:                            info.optimisticLockingExt, info.elements, quiet);
0873:                    break;
0874:                }
0875:            }
0876:
0877:            private void processTimestampOrRowVersionLocking(
0878:                    JdbcClass jdbcClass, ClassMetaData cmd, JdoExtension e,
0879:                    ArrayList jdbcElements, boolean quiet) {
0880:                boolean timestamp = jdbcClass.optimisticLocking == JdbcClass.OPTIMISTIC_LOCKING_TIMESTAMP;
0881:                JdoExtension[] nested = e == null ? null : e.nested;
0882:                if (nested != null
0883:                        && nested[0].key == JdoExtensionKeys.FIELD_NAME) {
0884:                    if (nested.length > 1) {
0885:                        RuntimeException x = BindingSupportImpl.getInstance()
0886:                                .runtime(
0887:                                        "Unexpected extension: "
0888:                                                + nested[1].getContext());
0889:                        cmd.addError(x, quiet);
0890:                    }
0891:                    String fieldName = nested[0].value;
0892:                    FieldMetaData fmd = cmd.getFieldMetaData(fieldName);
0893:                    if (fmd == null) {
0894:                        RuntimeException x = BindingSupportImpl.getInstance()
0895:                                .runtime(
0896:                                        "Field '" + fieldName + " not found\n"
0897:                                                + nested[0].getContext());
0898:                        cmd.addError(x, quiet);
0899:                    }
0900:                    int tc = fmd.typeCode;
0901:                    if (timestamp) {
0902:                        if (tc != MDStatics.DATE) {
0903:                            RuntimeException x = BindingSupportImpl
0904:                                    .getInstance()
0905:                                    .runtime(
0906:                                            "Field '"
0907:                                                    + fieldName
0908:                                                    + " is not a java.util.Date\n"
0909:                                                    + nested[0].getContext());
0910:                            fmd.addError(x, quiet);
0911:                        }
0912:                    } else {
0913:                        if (tc != MDStatics.INT && tc != MDStatics.SHORT
0914:                                && tc != MDStatics.BYTE) {
0915:                            RuntimeException x = BindingSupportImpl
0916:                                    .getInstance()
0917:                                    .runtime(
0918:                                            "Field '"
0919:                                                    + fieldName
0920:                                                    + " is not an int, short or byte\n"
0921:                                                    + nested[0].getContext());
0922:                            fmd.addError(x, quiet);
0923:                        }
0924:                    }
0925:                    cmd.optimisticLockingField = fmd;
0926:                    jdbcClass.optimisticLockingField = (JdbcSimpleField) fmd.storeField;
0927:                    fmd.setAutoSet(MDStatics.AUTOSET_BOTH);
0928:                } else {
0929:                    JdbcColumn tc = createColumn(nested, OPT_LOCK_FIELDNAME,
0930:                            timestamp ? (Class) Date.class : (Class) Short.TYPE);
0931:                    // generate a fake field for the column
0932:                    JdbcSimpleField f = jdbcClass.optimisticLockingField = new JdbcSimpleField();
0933:                    f.fake = true;
0934:                    f.col = tc;
0935:                    FieldMetaData fmd = f.fmd = new FieldMetaData();
0936:                    fmd.fake = true;
0937:                    fmd.category = MDStatics.CATEGORY_SIMPLE;
0938:                    fmd.primaryField = true;
0939:                    fmd.classMetaData = cmd;
0940:                    fmd.defaultFetchGroup = true;
0941:                    fmd.storeField = f;
0942:
0943:                    fmd.name = timestamp ? "jdoTimestamp" : "jdoVersion";
0944:
0945:                    fmd.persistenceModifier = MDStatics.PERSISTENCE_MODIFIER_PERSISTENT;
0946:                    fmd.setType(tc.javaType);
0947:                    fmd.setAutoSet(MDStatics.AUTOSET_BOTH);
0948:                    jdbcElements.add(f);
0949:                    cmd.optimisticLockingField = fmd;
0950:                }
0951:            }
0952:
0953:            /**
0954:             * Fill in extra meta data for FetchGroup's.
0955:             */
0956:            private void processFetchGroups(ClassMetaData cmd) {
0957:                FetchGroup[] groups = cmd.fetchGroups;
0958:                int groupsLen = groups == null ? 0 : groups.length;
0959:                for (int i = 0; i < groupsLen; i++) {
0960:                    FetchGroup g = groups[i];
0961:                    int totCols = 0;
0962:                    FetchGroupField[] fields = g.fields;
0963:                    if (fields == null) {
0964:                        continue;
0965:                    }
0966:                    int fieldsLen = fields.length;
0967:                    for (int j = 0; j < fieldsLen; j++) {
0968:                        FetchGroupField field = fields[j];
0969:                        FieldMetaData fmd = field.fmd;
0970:                        JdbcField jdbcField = (JdbcField) fmd.storeField;
0971:                        JdoExtension ext = field.extension;
0972:                        if (ext != null && ext.nested != null) {
0973:                            JdoExtension[] nested = ext.nested;
0974:                            int nestedLen = nested.length;
0975:                            for (int k = 0; k < nestedLen; k++) {
0976:                                JdoExtension e = nested[k];
0977:                                switch (e.key) {
0978:                                case JDBC_USE_JOIN:
0979:                                    try {
0980:                                        field.jdbcUseJoin = e
0981:                                                .getEnum(jdbcMDE.USE_JOIN_ENUM);
0982:                                    } catch (RuntimeException x) {
0983:                                        cmd.addError(x, quiet);
0984:                                    }
0985:                                    break;
0986:                                case JDBC_USE_KEY_JOIN:
0987:                                    if (fmd.category != MDStatics.CATEGORY_MAP) {
0988:                                        RuntimeException x = BindingSupportImpl
0989:                                                .getInstance()
0990:                                                .runtime(
0991:                                                        "The jdbc-use-key-join option is only "
0992:                                                                + "valid for Map fields\n"
0993:                                                                + e
0994:                                                                        .getContext());
0995:                                        cmd.addError(x, quiet);
0996:                                    }
0997:                                    try {
0998:                                        field.jdbcUseKeyJoin = e
0999:                                                .getEnum(jdbcMDE.USE_JOIN_ENUM);
1000:                                    } catch (RuntimeException x) {
1001:                                        cmd.addError(x, quiet);
1002:                                    }
1003:                                    break;
1004:                                default:
1005:                                    if (e.isJdbc()) {
1006:                                        MetaDataBuilder
1007:                                                .throwUnexpectedExtension(e);
1008:                                    }
1009:                                }
1010:                            }
1011:                        }
1012:                        if (jdbcField == null)
1013:                            continue;
1014:                        if (field.jdbcUseJoin == 0) {
1015:                            if (field.nextFetchGroup != null) {
1016:                                field.jdbcUseJoin = jdbcField.useJoin;
1017:                            } else {
1018:                                field.jdbcUseJoin = JdbcField.USE_JOIN_NO;
1019:                            }
1020:                        }
1021:                        if (field.jdbcUseKeyJoin == 0) {
1022:                            if (field.nextKeyFetchGroup != null) {
1023:                                field.jdbcUseKeyJoin = jdbcField
1024:                                        .getUseKeyJoin();
1025:                            } else {
1026:                                field.jdbcUseKeyJoin = JdbcField.USE_JOIN_NO;
1027:                            }
1028:                        }
1029:                        if (jdbcField.mainTableCols != null) {
1030:                            totCols += jdbcField.mainTableCols.length;
1031:                        }
1032:                    }
1033:                    g.jdbcTotalCols = totCols;
1034:                }
1035:            }
1036:
1037:            /**
1038:             * Process all ref and polyref fields.
1039:             */
1040:            private void processRefAndPolyRefFields(ClassMetaData cmd,
1041:                    boolean quiet) {
1042:                ArrayList elements = getClassElements(cmd);
1043:                int nelements = elements.size();
1044:                for (int i = 0; i < nelements; i++) {
1045:                    Object o = elements.get(i);
1046:                    if (o instanceof  JdbcRefField) {
1047:                        processRefField((JdbcRefField) o, quiet);
1048:                    } else if (o instanceof  JdbcPolyRefField) {
1049:                        JdbcPolyRefField f = (JdbcPolyRefField) o;
1050:                        f.processMetaData(f.fmd.jdoField, this );
1051:                    }
1052:                }
1053:            }
1054:
1055:            private void doConstraints(ClassMetaData cmd) {
1056:                for (int i = 0; i < cmd.fields.length; i++) {
1057:                    FieldMetaData fmd = cmd.fields[i];
1058:                    if (fmd.storeField instanceof  JdbcRefField) {
1059:                        createConstraint((JdbcRefField) fmd.storeField);
1060:                    }
1061:                }
1062:            }
1063:
1064:            /**
1065:             * Process all ref and collection fields.
1066:             */
1067:            private void processCollectionFields(ClassMetaData cmd,
1068:                    boolean quiet) {
1069:                if (cmd.horizontal)
1070:                    return;
1071:                ArrayList elements = getClassElements(cmd);
1072:                int nelements = elements.size();
1073:                for (int i = 0; i < nelements; i++) {
1074:                    Object o = elements.get(i);
1075:                    if (o instanceof  JdbcCollectionField) {
1076:                        processCollectionField((JdbcCollectionField) o, quiet);
1077:                    }
1078:                }
1079:            }
1080:
1081:            /**
1082:             * Complete a JdbcRefField except for column names.
1083:             */
1084:            private void processRefField(JdbcRefField f, boolean quiet) {
1085:                FieldMetaData fmd = f.fmd;
1086:                f.targetClass = fmd.typeMetaData;
1087:                JdbcClass target = (JdbcClass) f.targetClass.storeClass;
1088:                JdoField jdoField = fmd.jdoField;
1089:                JdoElement context = jdoField == null ? (JdoElement) fmd.typeMetaData.jdoClass
1090:                        : (JdoElement) jdoField;
1091:                processRefFieldImpl(target, f, fmd, context,
1092:                        jdoField == null ? null : jdoField.extensions, quiet);
1093:
1094:            }
1095:
1096:            public void processRefFieldImpl(JdbcClass target, JdbcRefField f,
1097:                    FieldMetaData fmd, JdoElement context,
1098:                    JdoExtension[] extensions, boolean quiet) {
1099:                if (target != null) {
1100:                    f.useJoin = target.useJoin;
1101:                } else {
1102:                    f.useJoin = JdbcRefField.USE_JOIN_NO;
1103:                }
1104:                if (f.useJoin == JdbcRefField.USE_JOIN_NO
1105:                        && fmd.isDefaultFetchGroupTrue()) {
1106:                    f.useJoin = JdbcRefField.USE_JOIN_OUTER;
1107:                }
1108:
1109:                JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder(
1110:                        fmd.classMetaData, this , f.targetClass, context,
1111:                        fmd.name, extensions, quiet);
1112:
1113:                f.cols = rdb.getCols();
1114:                if (rdb.getUseJoin() != 0)
1115:                    f.useJoin = rdb.getUseJoin();
1116:
1117:                for (int i = 0; i < f.cols.length; i++) {
1118:                    f.cols[i].comment = fmd.getCommentName();
1119:                }
1120:
1121:                boolean nulls = fmd.nullValue != MDStatics.NULL_VALUE_EXCEPTION;
1122:                int nc = f.cols.length;
1123:                for (int i = 0; i < nc; i++)
1124:                    f.cols[i].nulls = nulls;
1125:
1126:                // include this in the where clause for changed locking only if all
1127:                // columns support equalityTest
1128:                f.includeForChangedLocking = true;
1129:                for (int i = 0; i < nc; i++) {
1130:                    if (!f.cols[i].equalityTest) {
1131:                        f.includeForChangedLocking = false;
1132:                        break;
1133:                    }
1134:                }
1135:                f.constraintName = rdb.getConstraintName();
1136:                f.createConstraint = !rdb.isDoNotCreateConstraint();
1137:            }
1138:
1139:            private boolean isCircularRef(ClassMetaData cmd1, ClassMetaData cmd2) {
1140:                return jdbcClassReferenceGraph.isCircularRef(cmd1, cmd2);
1141:            }
1142:
1143:            private void createConstraint(JdbcRefField f) {
1144:                final JdbcClass jdbcClass = (JdbcClass) f.fmd.classMetaData.storeClass;
1145:                boolean createConstraint = f.createConstraint
1146:                        && f.targetClass != null
1147:                        && (!(f.fmd.nullValue != MDStatics.NULL_VALUE_EXCEPTION) || sqlDriver
1148:                                .isNullForeignKeyOk());
1149:
1150:                /**
1151:                 * If this class is involved in a cycle with the refering class then
1152:                 * don't create the constraint unless the user specifically specified a dependency.
1153:                 */
1154:                if (createConstraint
1155:                        && isCircularRef(jdbcClass.cmd, f.fmd.typeMetaData)) {
1156:                    if (!getClassInfo(jdbcClass.cmd.top)
1157:                            .getCreatedAfterClient().contains(
1158:                                    f.fmd.typeMetaData.top)) {
1159:                        createConstraint = false;
1160:                    }
1161:                }
1162:
1163:                if (createConstraint
1164:                        && jdbcClass.cmd.top == f.fmd.typeMetaData.top) {
1165:                    createConstraint = false;
1166:                }
1167:
1168:                // create constraint if required
1169:                if (createConstraint) {
1170:                    JdbcConstraint c = new JdbcConstraint();
1171:                    c.name = f.constraintName;
1172:                    c.src = jdbcClass.table;
1173:                    c.srcCols = f.cols;
1174:                    c.dest = ((JdbcClass) f.targetClass.storeClass).table;
1175:                    f.constraint = c;
1176:                    if (c.name != null) {
1177:                        nameGenerator.addRefConstraintName(c.src.name, c.name);
1178:                    }
1179:                }
1180:            }
1181:
1182:            /**
1183:             * Find the column in cols with the the supplied refField or null if none.
1184:             */
1185:            public JdbcColumn findColumn(List cols, JdbcSimpleField refField) {
1186:                for (int i = cols.size() - 1; i >= 0; i--) {
1187:                    JdbcColumn col = (JdbcColumn) cols.get(i);
1188:                    if (col.refField == refField)
1189:                        return col;
1190:                }
1191:                return null;
1192:            }
1193:
1194:            /**
1195:             * Complete a JdbcCollectionField.
1196:             */
1197:            private void processCollectionField(JdbcCollectionField f,
1198:                    boolean quiet) {
1199:                FieldMetaData fmd = f.fmd;
1200:                JdoField jdoField = fmd.jdoField;
1201:                JdoElement context;
1202:                if (jdoField == null) {
1203:                    if (fmd.typeMetaData == null) {
1204:                        context = fmd.classMetaData.jdoClass;
1205:                    } else {
1206:                        context = fmd.typeMetaData.jdoClass;
1207:                    }
1208:                } else {
1209:                    context = jdoField;
1210:                }
1211:                try {
1212:                    f.processMetaData(context, this , quiet);
1213:                } catch (RuntimeException e) {
1214:                    fmd.addError(e, quiet);
1215:                }
1216:            }
1217:
1218:            /**
1219:             * Creates key generators for all classes with keygen factories and
1220:             * extracts keygen tables from them. Also set the autoinc flag on
1221:             * the primary key of classes using a postInsert key generator.
1222:             */
1223:            private void createKeyGenerators(boolean quite) {
1224:                HashSet keygenSet = new HashSet();
1225:                HashSet keygenTables = new HashSet(17);
1226:                ClassMetaData[] classes = jmd.classes;
1227:                int clen = classes.length;
1228:                for (int i = 0; i < clen; i++) {
1229:                    ClassMetaData cmd = classes[i];
1230:                    if (cmd.horizontal)
1231:                        continue;
1232:                    if (cmd.pcSuperMetaData != null)
1233:                        continue;
1234:                    ClassInfo info = getClassInfo(cmd);
1235:                    JdbcKeyGeneratorFactory f = info.keyGenFactory;
1236:                    if (f == null)
1237:                        continue;
1238:                    JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1239:                    JdbcKeyGenerator keygen;
1240:                    try {
1241:                        keygen = f.createJdbcKeyGenerator(cmd.qname,
1242:                                jdbcClass.table, info.keyGenFactoryArgs);
1243:                    } catch (RuntimeException e) {
1244:                        cmd.addError(BindingSupportImpl.getInstance().runtime(
1245:                                e.getMessage() + "\n"
1246:                                        + cmd.jdoClass.getContext(), e), quite);
1247:                        continue;
1248:                    }
1249:
1250:                    // recursively set keygen on class and subclasses
1251:                    jdbcClass.setJdbcKeyGenerator(keygen);
1252:
1253:                    if (keygenSet.contains(keygen))
1254:                        continue;
1255:                    keygenSet.add(keygen);
1256:                    keygen.addKeyGenTables(keygenTables, this );
1257:
1258:                    // set the autoinc flag on the primary key if postInsert keygen
1259:                    if (keygen.isPostInsertGenerator()) {
1260:                        jdbcClass.table.pk[0].autoinc = true;
1261:                        //for sybase this column's type must change to numeric
1262:                        //all subclass column's must also be updated
1263:                        sqlDriver.updateClassForPostInsertKeyGen(cmd,
1264:                                mappingResolver);
1265:                    }
1266:                }
1267:                JdbcMetaData jdbcMetaData = (JdbcMetaData) jmd.jdbcMetaData;
1268:                jdbcMetaData.keyGenTables = new JdbcTable[keygenTables.size()];
1269:                keygenTables.toArray(jdbcMetaData.keyGenTables);
1270:            }
1271:
1272:            /**
1273:             * Name field columns without names and create the cols array on each
1274:             * class table from the jdbcElements collected so far. It will
1275:             * recursively process subclasses as required. Fake elements are
1276:             * collected at the same time and added to ClassMetaData.fields.
1277:             */
1278:            private void finalizeFakesAndTableColumns(ClassMetaData cmd) {
1279:                ArrayList elements = getClassElements(cmd);
1280:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1281:                if (elements != null) {
1282:                    collectSubclassElements(cmd, elements);
1283:
1284:                    JdbcNameGenerator nameGen = nameGenerator;
1285:                    String tableName = jdbcClass.tableName;
1286:
1287:                    // make sure the classIdCol has a name
1288:                    JdbcColumn classIdCol = jdbcClass.classIdCol;
1289:                    if (classIdCol != null) {
1290:                        if (classIdCol.name == null) {
1291:                            classIdCol.name = nameGen
1292:                                    .generateClassIdColumnName(tableName);
1293:                        } else {
1294:                            nameGen.addColumnName(tableName, classIdCol.name);
1295:                        }
1296:                    }
1297:
1298:                    // find all the JdbcColumn's in all elements and find fake
1299:                    // fields
1300:                    ArrayList cols = new ArrayList(elements.size());
1301:                    ArrayList fakes = new ArrayList();
1302:                    JdbcTable table = jdbcClass.table;
1303:                    for (int i = 0; i < elements.size(); i++) {
1304:                        Object o = elements.get(i);
1305:                        if (o instanceof  JdbcField) {
1306:                            JdbcField f = (JdbcField) o;
1307:                            f.setMainTable(table);
1308:                            if (!f.fmd.primaryKey)
1309:                                f.nameColumns(tableName, nameGen);
1310:                            int pos = cols.size();
1311:                            f.addMainTableCols(cols);
1312:                            // make sure cols from subclasses allow nulls
1313:                            if (f.fmd.classMetaData.pcSuperMetaData != null) {
1314:                                int pos2 = cols.size();
1315:                                for (int j = pos; j < pos2; j++) {
1316:                                    JdbcColumn sc = (JdbcColumn) cols.get(j);
1317:                                    sc.nulls = true;
1318:                                }
1319:                            }
1320:                            if (f.fake) {
1321:                                fakes.add(f);
1322:                            }
1323:                        } else { // must be a column
1324:                            JdbcColumn c = (JdbcColumn) o;
1325:                            c.setTable(table);
1326:                            cols.add(c);
1327:                        }
1328:                    }
1329:
1330:                    //this done after all the naming has taken place.
1331:                    doNullIndicatorColumn(cmd, elements);
1332:
1333:                    // add the fakes (if any) to cmd.fields
1334:                    int numFakes = fakes.size();
1335:                    if (numFakes > 0 && cmd.fields != null) {
1336:                        int n = cmd.fields.length;
1337:                        FieldMetaData[] a = new FieldMetaData[n + numFakes];
1338:                        System.arraycopy(cmd.fields, 0, a, 0, n);
1339:                        for (int i = 0; i < numFakes; i++, n++) {
1340:                            JdbcField jdbcField = (JdbcField) fakes.get(i);
1341:                            a[n] = jdbcField.fmd;
1342:                        }
1343:                        cmd.fields = a;
1344:                    }
1345:
1346:                    // do a final sanity check on each column and set the table reference
1347:                    int nc = cols.size();
1348:                    JdbcColumn[] a = new JdbcColumn[nc];
1349:                    cols.toArray(a);
1350:                    for (int i = 0; i < nc; i++) {
1351:                        JdbcColumn c = a[i];
1352:                        if (c.name == null) {
1353:                            throw BindingSupportImpl.getInstance().internal(
1354:                                    "Column has no name: " + c + "\n"
1355:                                            + cmd.jdoClass.getContext());
1356:                        }
1357:                        if (c.jdbcType == Types.NULL) {
1358:                            throw BindingSupportImpl.getInstance().internal(
1359:                                    "Column has NULL jdbcType: " + c + "\n"
1360:                                            + cmd.jdoClass.getContext());
1361:                        }
1362:                        if (c.table == null) {
1363:                            throw BindingSupportImpl.getInstance().internal(
1364:                                    "Column null table: " + c + "\n"
1365:                                            + cmd.jdoClass.getContext());
1366:                        }
1367:                        if (!sqlDriver
1368:                                .isBatchingSupportedForJdbcType(c.jdbcType)) {
1369:                            jdbcClass.noBatching = true;
1370:                        }
1371:                    }
1372:
1373:                    // set the cols array
1374:                    jdbcClass.table.cols = a;
1375:                }
1376:
1377:                // recursively process all of our subclasses
1378:                ClassMetaData[] subclasses = cmd.pcSubclasses;
1379:                if (subclasses == null)
1380:                    return;
1381:                for (int i = 0; i < subclasses.length; i++) {
1382:                    ((JdbcClass) subclasses[i].storeClass)
1383:                            .setClassIdCol(jdbcClass.classIdCol);
1384:                    finalizeFakesAndTableColumns(subclasses[i]);
1385:                }
1386:            }
1387:
1388:            /**
1389:             * Go through all the embedded reference fields on the supplied cmd and find
1390:             * nullindicator columns.
1391:             */
1392:            private void doNullIndicatorColumn(ClassMetaData cmd,
1393:                    ArrayList elements) {
1394:                //************** ignored for now **********************.
1395:                if (true)
1396:                    return;
1397:                //************** ignored for now **********************.
1398:                FieldMetaData[] fmds = cmd.fields;
1399:                for (int i = 0; i < fmds.length; i++) {
1400:                    FieldMetaData fmd = fmds[i];
1401:                    if (fmd.isEmbeddedRef()) {
1402:                        if (fmd.jdoField != null
1403:                                && fmd.jdoField.extensions != null) {
1404:                            JdoExtension ext = JdoExtension.find(
1405:                                    JdoExtensionKeys.NULL_INDICATOR,
1406:                                    fmd.jdoField.extensions);
1407:                            if (ext != null) {
1408:                                boolean extFound = false;
1409:                                //expect a jdbc-column-name
1410:                                if (ext.nested != null) {
1411:                                    JdoExtension colNameExt = ext.nested[0];
1412:                                    if (colNameExt.key == JdoExtensionKeys.JDBC_COLUMN_NAME) {
1413:                                        extFound = true;
1414:                                        //must check to see if we have any column in the table with that name
1415:                                        boolean createColumn = true;
1416:                                        for (int l = 0; l < elements.size(); l++) {
1417:                                            Object o1 = elements.get(l);
1418:                                            if (o1 instanceof  JdbcSimpleField) {
1419:                                                JdbcSimpleField sf = (JdbcSimpleField) o1;
1420:                                                if (sf.col.name == ext.value) {
1421:                                                    createColumn = false;
1422:                                                }
1423:                                            }
1424:                                        }
1425:                                        if (createColumn) {
1426:                                            JdbcColumn col = createColumn(
1427:                                                    ext.nested,
1428:                                                    CLASS_ID_FIELDNAME,
1429:                                                    Integer.TYPE);
1430:                                            JdbcSimpleField f = new JdbcSimpleField();
1431:                                            f.fake = true;
1432:                                            f.col = col;
1433:                                            FieldMetaData nullFmd = f.fmd = new FieldMetaData();
1434:                                            nullFmd.fake = true;
1435:                                            nullFmd.category = MDStatics.CATEGORY_SIMPLE;
1436:                                            nullFmd.classMetaData = cmd;
1437:                                            nullFmd.defaultFetchGroup = true;
1438:                                            nullFmd.storeField = f;
1439:                                            nullFmd.name = fmd.name
1440:                                                    + "_null_indicator";
1441:                                            nullFmd.persistenceModifier = MDStatics.PERSISTENCE_MODIFIER_PERSISTENT;
1442:                                            nullFmd.setType(col.javaType);
1443:                                            fmd.setNullIndicatorFmd(nullFmd);
1444:                                            elements.add(f);
1445:                                        }
1446:                                    }
1447:                                }
1448:                                if (!extFound) {
1449:                                    throw BindingSupportImpl
1450:                                            .getInstance()
1451:                                            .unsupported(
1452:                                                    "Found a '"
1453:                                                            + JdoExtension
1454:                                                                    .toKeyString(JdoExtensionKeys.NULL_INDICATOR)
1455:                                                            + "' extension with no '"
1456:                                                            + JdoExtension
1457:                                                                    .toKeyString(JdoExtensionKeys.JDBC_COLUMN_NAME)
1458:                                                            + "' nested extension");
1459:                                }
1460:                            }
1461:                        }
1462:                    }
1463:                }
1464:            }
1465:
1466:            /**
1467:             * Name all constraints without names and create the constraint arrays
1468:             * on class tables.
1469:             */
1470:            private void finalizeConstraints(ClassMetaData cmd) {
1471:                ClassInfo info = getClassInfo(cmd);
1472:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1473:                JdbcField[] fields = jdbcClass.fields;
1474:                int len = fields.length;
1475:                ArrayList cons = new ArrayList();
1476:                JdbcConstraint pkFkConstraint = info.pkFkConstraint;
1477:                if (pkFkConstraint != null) {
1478:                    if (pkFkConstraint.name == null) {
1479:                        pkFkConstraint.generateName(nameGenerator);
1480:                    }
1481:                    cons.add(pkFkConstraint);
1482:                }
1483:                JdbcTable table = jdbcClass.table;
1484:                for (int i = 0; i < len; i++) {
1485:                    JdbcField field = fields[i];
1486:                    if (field != null && field.mainTable == jdbcClass.table) {
1487:                        field.addConstraints(cons);
1488:                    }
1489:                }
1490:                int n = cons.size();
1491:                if (n > 0) {
1492:                    table.addConstraints(cons);
1493:                }
1494:            }
1495:
1496:            /**
1497:             * Recursively add all elements from all subclasses of cmd that are
1498:             * stored in the same table to elements. Any class so added has its
1499:             * elements removed from the map indicating that it has been processed.
1500:             */
1501:            private void collectSubclassElements(ClassMetaData cmd,
1502:                    ArrayList elements) {
1503:                ClassMetaData[] subclasses = cmd.pcSubclasses;
1504:                if (subclasses == null)
1505:                    return;
1506:                for (int i = 0; i < subclasses.length; i++) {
1507:                    ClassMetaData sc = subclasses[i];
1508:                    if (((JdbcClass) sc.storeClass).table == ((JdbcClass) cmd.storeClass).table) {
1509:                        ClassInfo scInfo = getClassInfo(sc);
1510:                        elements.addAll(scInfo.elements);
1511:                        scInfo.elements = null;
1512:                        collectSubclassElements(sc, elements);
1513:                    }
1514:                }
1515:            }
1516:
1517:            /**
1518:             * Find the primary key (datastore or application) for cmd and make sure
1519:             * all the columns have names. If the identity-type is datastore and
1520:             * there is no primary key column then create one. This will recursively
1521:             * process any PC subclasses.
1522:             */
1523:            private void processPrimaryKey(ClassMetaData cmd, boolean quiet) {
1524:                //        if (cmd.horizontal) return;
1525:                if (cmd.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
1526:                    processPrimaryKeyAppIdentity(cmd, quiet);
1527:                } else {
1528:                    processPrimaryKeyDatastoreIdentity(cmd);
1529:                }
1530:
1531:                // create subclass table fk constraint to base table if needed
1532:                ClassInfo info = getClassInfo(cmd);
1533:                ClassMetaData pccmd = cmd.pcSuperMetaData;
1534:                if (pccmd != null
1535:                        && ((JdbcClass) cmd.storeClass).table != ((JdbcClass) pccmd.storeClass).table) {
1536:                    JdbcConstraint c = new JdbcConstraint();
1537:                    c.name = info.pkFkConstraintName;
1538:                    c.src = ((JdbcClass) cmd.storeClass).table;
1539:                    c.srcCols = ((JdbcClass) cmd.storeClass).table.pk;
1540:                    c.dest = ((JdbcClass) pccmd.storeClass).table;
1541:                    if (c.name != null) {
1542:                        nameGenerator.addRefConstraintName(c.src.name, c.name);
1543:                    }
1544:                    info.pkFkConstraint = c;
1545:                }
1546:
1547:                if (cmd.pcSubclasses == null)
1548:                    return;
1549:                for (int j = 0; j < cmd.pcSubclasses.length; j++) {
1550:                    processPrimaryKey(cmd.pcSubclasses[j], quiet);
1551:                }
1552:            }
1553:
1554:            /**
1555:             * Find the primary key for datastore identity class for cmd and make sure
1556:             * all the columns have names. If there is no primary key column then
1557:             * create one.
1558:             */
1559:            private void processPrimaryKeyDatastoreIdentity(ClassMetaData cmd) {
1560:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1561:                JdbcTable table = jdbcClass.table;
1562:                JdbcColumn pkcol = null;
1563:
1564:                ArrayList jdbcElements = getClassElements(cmd);
1565:                int elen = jdbcElements.size();
1566:                for (int i = 0; i < elen; i++) {
1567:                    Object o = jdbcElements.get(i);
1568:                    if (!(o instanceof  JdbcColumn))
1569:                        continue;
1570:                    JdbcColumn c = (JdbcColumn) o;
1571:                    if (c.pk) {
1572:                        if (pkcol != null) {
1573:                            throw BindingSupportImpl
1574:                                    .getInstance()
1575:                                    .runtime(
1576:                                            "Class "
1577:                                                    + cmd.qname
1578:                                                    + " has multiple jdbc-primary-key extensions\n"
1579:                                                    + cmd.jdoClass.getContext());
1580:                        }
1581:                        pkcol = c;
1582:                    }
1583:                }
1584:                if (cmd.pcSuperMetaData != null) {
1585:                    if (pkcol != null) {
1586:                        throw BindingSupportImpl
1587:                                .getInstance()
1588:                                .runtime(
1589:                                        "Class "
1590:                                                + cmd.qname
1591:                                                + " has a "
1592:                                                + "persistence-capable-superclass so use the inheritance "
1593:                                                + "extension to specify its primary-key\n"
1594:                                                + cmd.jdoClass.getContext());
1595:                    }
1596:                    // if subclass is stored in its own table then use the inheritance
1597:                    // extension to build a reference to the superclass
1598:                    if (table != ((JdbcClass) cmd.pcSuperMetaData.storeClass).table) {
1599:                        createVerticalInheritancePK(cmd);
1600:                    }
1601:                } else {
1602:                    if (pkcol == null) {
1603:                        pkcol = createColumn(null, DATASTORE_PK_FIELDNAME,
1604:                                Integer.TYPE);
1605:                        jdbcElements.add(0, pkcol);
1606:                    }
1607:                    // make sure the columns has a name
1608:                    if (pkcol.name != null) {
1609:                        try {
1610:                            nameGenerator.addColumnName(table.name, pkcol.name);
1611:                        } catch (IllegalArgumentException e) {
1612:                            throw BindingSupportImpl.getInstance().runtime(
1613:                                    "Invalid jdbc-column-name for datastore identity primary key: "
1614:                                            + e.getMessage() + "\n"
1615:                                            + cmd.jdoClass.getContext());
1616:                        }
1617:                    } else {
1618:                        pkcol.name = nameGenerator
1619:                                .generateDatastorePKName(table.name);
1620:                    }
1621:                    table.setPk(new JdbcColumn[] { pkcol });
1622:                }
1623:            }
1624:
1625:            /**
1626:             * Fill in the primary key for a subclass mapped using vertical
1627:             * inheritance using the inheritance extension to build a reference to the
1628:             * superclass.
1629:             */
1630:            private void createVerticalInheritancePK(ClassMetaData cmd) {
1631:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1632:                JdbcTable table = jdbcClass.table;
1633:                JdbcTable super Table = ((JdbcClass) cmd.pcSuperMetaData.storeClass).table;
1634:                JdoExtension inheritance = getClassInfo(cmd).inheritance;
1635:                JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder(cmd,
1636:                        this , cmd.pcSuperMetaData, inheritance, null,
1637:                        inheritance == null ? null : inheritance.nested, quiet);
1638:                JdbcColumn[] a = rdb.getCols();
1639:                for (int i = 0; i < a.length; i++) {
1640:                    if (a[i].name == null)
1641:                        a[i].name = super Table.pk[i].name;
1642:                    a[i].pk = true;
1643:                }
1644:                table.setPk(a);
1645:                ArrayList jdbcElements = getClassElements(cmd);
1646:                for (int i = 0; i < a.length; i++) {
1647:                    try {
1648:                        a[i].addColumnNames(table.name, nameGenerator);
1649:                    } catch (IllegalArgumentException e) {
1650:                        throw BindingSupportImpl.getInstance().runtime(
1651:                                "Invalid jdbc-column-name: " + e.getMessage()
1652:                                        + "\n" + inheritance.getContext());
1653:                    }
1654:                    jdbcElements.add(i, a[i]);
1655:                }
1656:            }
1657:
1658:            /**
1659:             * Find the primary key for application identity class cmd and make sure
1660:             * all the columns have names.
1661:             */
1662:            private void processPrimaryKeyAppIdentity(ClassMetaData cmd,
1663:                    boolean quiet) {
1664:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1665:                JdbcTable table = jdbcClass.table;
1666:                JdbcNameGenerator ng = nameGenerator;
1667:                FieldMetaData[] fields = cmd.pkFields;
1668:                JdbcColumn[] pkcols = null;
1669:                int pkFieldCount = fields == null ? 0 : fields.length;
1670:                if (fields != null) {
1671:                    pkcols = new JdbcColumn[pkFieldCount];
1672:                    for (int i = 0; i < pkFieldCount; i++) {
1673:                        try {
1674:                            JdbcSimpleField jdbcSimpleField = (JdbcSimpleField) fields[i].storeField;
1675:                            pkcols[i] = jdbcSimpleField.col;
1676:                            pkcols[i].refField = jdbcSimpleField;
1677:                        } catch (ClassCastException e) {
1678:                            RuntimeException x = BindingSupportImpl
1679:                                    .getInstance()
1680:                                    .runtime(
1681:                                            "Only simple fields may be mapped as Primary Key's.\n"
1682:                                                    + cmd.jdoClass.getContext());
1683:                            cmd.addError(x, quiet);
1684:                        }
1685:                    }
1686:                }
1687:                ClassMetaData pccmd = cmd.pcSuperMetaData;
1688:                if (pccmd != null
1689:                        && ((JdbcClass) pccmd.storeClass).inheritance != JdbcClass.INHERITANCE_HORIZONTAL) {
1690:                    if (pkcols != null) {
1691:                        throw BindingSupportImpl
1692:                                .getInstance()
1693:                                .runtime(
1694:                                        "Class "
1695:                                                + cmd.qname
1696:                                                + " has a "
1697:                                                + "persistence-capable-superclass so use the inheritance "
1698:                                                + "extension to specify its primary-key\n"
1699:                                                + cmd.jdoClass.getContext());
1700:                    }
1701:                    // if subclass is stored in its own table then use the inheritance
1702:                    // extension to build a reference to the superclass
1703:                    if (table != ((JdbcClass) pccmd.storeClass).table) {
1704:                        createVerticalInheritancePK(cmd);
1705:                    }
1706:                } else {
1707:                    if (pkcols == null) {
1708:                        RuntimeException e = BindingSupportImpl.getInstance()
1709:                                .runtime(
1710:                                        "Class " + cmd.qname
1711:                                                + " has application identity "
1712:                                                + "but no primary-key fields\n"
1713:                                                + cmd.jdoClass.getContext());
1714:                        cmd.addError(e, quiet);
1715:                    } else {
1716:                        for (int i = 0; i < pkFieldCount; i++) {
1717:                            String cn = pkcols[i].name;
1718:                            if (cn == null) {
1719:                                pkcols[i].name = ng.generateFieldColumnName(
1720:                                        table.name, fields[i].name, true);
1721:                            } else {
1722:                                try {
1723:                                    ng.addColumnName(table.name, cn);
1724:                                } catch (IllegalArgumentException x) {
1725:                                    throw BindingSupportImpl
1726:                                            .getInstance()
1727:                                            .runtime(
1728:                                                    "Invalid jdbc-column-name: "
1729:                                                            + x.getMessage()
1730:                                                            + "\n"
1731:                                                            + cmd.jdoClass
1732:                                                                    .getContext());
1733:                                }
1734:                            }
1735:                        }
1736:                        table.setPk(pkcols);
1737:                    }
1738:                }
1739:            }
1740:
1741:            /**
1742:             * Make sure the persistent capable class cmd has a table and
1743:             * recursively process all of its subclasses. NOP if cmd is not
1744:             * a base class.
1745:             */
1746:            private void processBaseClassTable(ClassMetaData cmd) {
1747:                ClassMetaData pccmd = cmd.pcSuperMetaData;
1748:                if (pccmd != null)
1749:                    return;
1750:                createClassTable(cmd);
1751:                JdbcClass jdbcClass = ((JdbcClass) cmd.storeClass);
1752:                if (cmd.horizontal) {
1753:                    jdbcClass.doNotCreateTable = true;
1754:                }
1755:                if (cmd.pcSubclasses == null)
1756:                    return;
1757:                for (int j = 0; j < cmd.pcSubclasses.length; j++) {
1758:                    processSubclassTable(cmd.pcSubclasses[j]);
1759:                }
1760:            }
1761:
1762:            private void createClassTable(ClassMetaData cmd) {
1763:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1764:                JdbcTable table = new JdbcTable();
1765:                table.sqlDriver = sqlDriver;
1766:                table.name = jdbcClass.tableName;
1767:                table.comment = cmd.qname;
1768:                if (table.name == null) {
1769:                    table.name = nameGenerator
1770:                            .generateClassTableName(cmd.qname);
1771:                } else {
1772:                    addTableName(table, cmd);
1773:                }
1774:                jdbcClass.setTable(table);
1775:                fillTablePkConstraintName(cmd, table);
1776:            }
1777:
1778:            /**
1779:             * Make sure a persistent capable subclass cmd has a table and
1780:             * recursively process all of its subclasses.
1781:             */
1782:            private void processSubclassTable(ClassMetaData cmd) {
1783:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1784:                ClassMetaData pccmd = cmd.pcSuperMetaData;
1785:                switch (jdbcClass.inheritance) {
1786:                case JdbcClass.INHERITANCE_FLAT:
1787:                    jdbcClass.setTable(((JdbcClass) pccmd.storeClass).table);
1788:                    break;
1789:                case JdbcClass.INHERITANCE_VERTICAL:
1790:                    createClassTable(cmd);
1791:                    break;
1792:                default:
1793:                    throw BindingSupportImpl.getInstance().internal(
1794:                            "Unknown inheritance strategy: "
1795:                                    + jdbcClass.inheritance + " for "
1796:                                    + cmd.qname);
1797:                }
1798:
1799:                if (cmd.pcSubclasses == null)
1800:                    return;
1801:                for (int j = 0; j < cmd.pcSubclasses.length; j++) {
1802:                    processSubclassTable(cmd.pcSubclasses[j]);
1803:                }
1804:            }
1805:
1806:            private void addTableName(JdbcTable table, ClassMetaData cmd) {
1807:                try {
1808:                    nameGenerator.addTableName(table.name);
1809:                } catch (IllegalArgumentException x) {
1810:                    throw BindingSupportImpl.getInstance().runtime(
1811:                            "Invalid jdbc-table-name: " + x.getMessage() + "\n"
1812:                                    + cmd.jdoClass.getContext());
1813:                }
1814:            }
1815:
1816:            private void fillTablePkConstraintName(ClassMetaData cmd,
1817:                    JdbcTable table) {
1818:                table.pkConstraintName = getClassInfo(cmd).pkConstraintName;
1819:                if (table.pkConstraintName == null) {
1820:                    table.pkConstraintName = nameGenerator
1821:                            .generatePkConstraintName(table.name);
1822:                } else {
1823:                    try {
1824:                        nameGenerator.addPkConstraintName(table.name,
1825:                                table.pkConstraintName);
1826:                    } catch (IllegalArgumentException e) {
1827:                        throw BindingSupportImpl.getInstance().runtime(
1828:                                "Invalid jdbc-pk-constraint-name: "
1829:                                        + e.getMessage() + "\n"
1830:                                        + cmd.jdoClass.getContext(), e);
1831:                    }
1832:                }
1833:            }
1834:
1835:            /**
1836:             * Create meta data for cmd and all of its subclasses and figure out
1837:             * everything that does not require access to JdbcClass objects other
1838:             * than its superclasses as they may not exist yet.
1839:             */
1840:            private void createJdbcClass(ClassMetaData cmd, boolean quiet) {
1841:                ClassInfo info = new ClassInfo();
1842:                info.cmd = cmd;
1843:                classInfoMap.put(cmd, info);
1844:                JdbcClass jdbcClass = new JdbcClass(sqlDriver);
1845:                cmd.storeClass = jdbcClass;
1846:                jdbcClass.cmd = cmd;
1847:                JdoClass jdoClass = cmd.jdoClass;
1848:
1849:                // fill in defaults that may be overwritten by extensions
1850:                jdbcClass.optimisticLocking = jdbcConfig.jdbcOptimisticLocking;
1851:                info.optimisticLockingExt = null;
1852:
1853:                jdbcClass.useJoin = JdbcRefField.USE_JOIN_OUTER;
1854:                jdbcClass.doNotCreateTable = jdbcConfig.jdbcDoNotCreateTable;
1855:
1856:                // default the descriminator value
1857:                switch (jdbcConfig.defaultClassId) {
1858:                case JdbcConfig.DEFAULT_CLASS_ID_FULLNAME:
1859:                    jdbcClass.jdbcClassId = cmd.qname;
1860:                    break;
1861:                case JdbcConfig.DEFAULT_CLASS_ID_NAME:
1862:                    jdbcClass.jdbcClassId = cmd.jdoClass.name;
1863:                    break;
1864:                default:
1865:                    jdbcClass.jdbcClassId = cmd.classIdString;
1866:                }
1867:
1868:                if (cmd.pcSuperMetaData != null) {
1869:                    if (getClassInfo(cmd.top).noClassIdCol) {
1870:                        jdbcClass.inheritance = JdbcClass.INHERITANCE_VERTICAL;
1871:                    } else {
1872:                        jdbcClass.inheritance = jdbcConfig.inheritance;
1873:                    }
1874:                } else {
1875:                    jdbcClass.inheritance = jdbcConfig.inheritance;
1876:                    info.noClassIdCol = jdbcConfig.defaultClassId == JdbcConfig.DEFAULT_CLASS_ID_NO;
1877:                }
1878:
1879:                if (cmd.identityType == MDStatics.IDENTITY_TYPE_DATASTORE) {
1880:                    info.keyGenFactory = keyGenRegistry
1881:                            .getFactory(jdbcConfig.jdbcKeyGenerator);
1882:                    info.keyGenFactoryArgs = info.keyGenFactory
1883:                            .createArgsBean();
1884:                    BeanUtils.setProperties(info.keyGenFactoryArgs,
1885:                            jdbcConfig.jdbcKeyGeneratorProps);
1886:                }
1887:
1888:                // fill in whatever we can from extensions, fields etc
1889:                JdoElement[] elements = jdoClass.elements;
1890:                int n = elements.length;
1891:                ArrayList jdbcElements = info.elements = new ArrayList(n);
1892:                for (int i = 0; i < n; i++) {
1893:                    JdoElement o = elements[i];
1894:                    if (o instanceof  JdoExtension) {
1895:                        try {
1896:                            processClassExtensionPass1(cmd, (JdoExtension) o,
1897:                                    jdbcElements, quiet);
1898:                        } catch (RuntimeException e) {
1899:                            cmd.addError(e, quiet);
1900:                        }
1901:                    } else { // must be a JdoField
1902:                        JdoField jdoField = (JdoField) o;
1903:                        FieldMetaData fmd = cmd.getFieldMetaData(jdoField.name);
1904:                        if (fmd == null)
1905:                            continue; // must be PERSISTENT_NONE
1906:
1907:                        if (fmd.isEmbeddedRef()) {
1908:                            continue;
1909:                        }
1910:
1911:                        JdbcField f = null;
1912:                        f = createJdbcField(fmd, quiet);
1913:                        if (f != null) {
1914:                            f.fmd = fmd;
1915:                            fmd.storeField = f;
1916:                            fmd.primaryField = true;
1917:                            jdbcElements.add(f);
1918:                        }
1919:                    }
1920:                }
1921:
1922:                // create JdbcField's for all persistent fields not yet found
1923:                FieldMetaData[] fields = cmd.fields;
1924:                n = fields.length;
1925:                for (int i = 0; i < n; i++) {
1926:                    FieldMetaData fmd = fields[i];
1927:                    if (fmd.storeField != null || fmd.isEmbeddedRef())
1928:                        continue;
1929:                    JdbcField f = createJdbcField(fmd, quiet);
1930:                    if (f != null) {
1931:                        f.fmd = fmd;
1932:                        fmd.storeField = f;
1933:                        fmd.primaryField = true;
1934:                        jdbcElements.add(f);
1935:                    }
1936:                }
1937:
1938:                cmd.changedOptimisticLocking = jdbcClass.optimisticLocking == JdbcClass.OPTIMISTIC_LOCKING_CHANGED;
1939:
1940:                // process subclasses
1941:                if (cmd.pcSubclasses != null) {
1942:                    for (int i = cmd.pcSubclasses.length - 1; i >= 0; i--) {
1943:                        createJdbcClass(cmd.pcSubclasses[i], quiet);
1944:                    }
1945:                }
1946:            }
1947:
1948:            /**
1949:             * Create the classIdCol and initialise the jdbcClassId to the correct type.
1950:             * This is called on the least derived class in the hierarchy and then
1951:             * recursively called on subs.
1952:             */
1953:            private void processClassIdCol(ClassMetaData cmd, boolean quiet,
1954:                    HashMap classIdMap) {
1955:                ClassInfo info = getClassInfo(cmd);
1956:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
1957:
1958:                if (cmd.pcSuperMetaData == null) {
1959:                    if (!info.noClassIdCol && cmd.pcSubclasses != null) {
1960:                        // topmost class so we need to create the column
1961:                        boolean intClassId = jdbcClass
1962:                                .isIntJdbcClassIdHeirachy();
1963:                        Class javaType = intClassId ? (Class) Integer.TYPE
1964:                                : (Class) String.class;
1965:
1966:                        if (info.classIdExt != null
1967:                                && info.classIdExt.nested != null) {
1968:                            // if there is a jdbc-class-id extension with nested extensions
1969:                            // then use these to create the column
1970:                            JdbcColumn col = jdbcClass.classIdCol = createColumn(
1971:                                    info.classIdExt.nested, CLASS_ID_FIELDNAME,
1972:                                    javaType);
1973:                            if (col.pk) {
1974:                                throw BindingSupportImpl
1975:                                        .getInstance()
1976:                                        .runtime(
1977:                                                "The jdbc-primary-key option is "
1978:                                                        + "not allowed for a jdbc-class-id column\n"
1979:                                                        + info.classIdExt
1980:                                                                .getContext());
1981:                            }
1982:                            info.elements.add(col);
1983:                        } else {
1984:                            // no extensions so just create a suitable column
1985:                            jdbcClass.classIdCol = createColumn(null,
1986:                                    CLASS_ID_FIELDNAME, javaType);
1987:                            info.elements.add(jdbcClass.classIdCol);
1988:                        }
1989:
1990:                        // convert heirachy jdbcClassId to Integer if needed
1991:                        if (intClassId)
1992:                            jdbcClass.convertJdbcClassIdToInteger();
1993:                    } else {
1994:                        jdbcClass.jdbcClassId = null;
1995:                    }
1996:                } else { // not the topmost class
1997:                    if (getClassInfo(cmd.top).noClassIdCol) {
1998:                        if (jdbcClass.inheritance != JdbcClass.INHERITANCE_VERTICAL) {
1999:                            // Flat inheritance and no descriminator is allowed if
2000:                            // there is no fanout in the heirachy (i.e. each class
2001:                            // has 0 or 1 subclasses). Only instances of the leaf
2002:                            // class may be persisted and only instances of the leaf
2003:                            // class will be returned from the database.
2004:                            if (cmd.pcSuperMetaData.pcSubclasses.length > 1) {
2005:                                throw BindingSupportImpl
2006:                                        .getInstance()
2007:                                        .invalidOperation(
2008:                                                "Class "
2009:                                                        + cmd.qname
2010:                                                        + " must use vertical inheritance as\n"
2011:                                                        + "it has siblings and the base class "
2012:                                                        + "does not have a descriminator (jdo_class) column\n"
2013:                                                        + cmd.jdoClass
2014:                                                                .getContext());
2015:                            }
2016:                            // only leaf class instances allowed
2017:                            cmd.pcSuperMetaData.instancesNotAllowed = true;
2018:                            // read superclass(es) as us instead
2019:                            for (ClassMetaData i = cmd.pcSuperMetaData; i != null; i = i.pcSuperMetaData) {
2020:                                ((JdbcClass) i.storeClass).readAsClass = cmd;
2021:                            }
2022:                        }
2023:                        jdbcClass.jdbcClassId = null;
2024:                    }
2025:
2026:                    // subclass so fill in the classIdCol from the topmost class
2027:                    jdbcClass.classIdCol = ((JdbcClass) cmd.top.storeClass).classIdCol;
2028:                }
2029:
2030:                // check for duplicate descriminator values in the heirachy
2031:                if (jdbcClass.jdbcClassId != null) {
2032:                    ClassMetaData other = (ClassMetaData) classIdMap
2033:                            .get(jdbcClass.jdbcClassId);
2034:                    if (other != null) {
2035:                        throw BindingSupportImpl.getInstance()
2036:                                .invalidOperation(
2037:                                        "Class " + cmd.qname
2038:                                                + " has same jdbc-class-id as "
2039:                                                + other.qname + ": '"
2040:                                                + jdbcClass.jdbcClassId + "'\n"
2041:                                                + cmd.jdoClass.getContext());
2042:                    }
2043:                    classIdMap.put(jdbcClass.jdbcClassId, cmd);
2044:                }
2045:
2046:                // process subclasses
2047:                if (cmd.pcSubclasses != null) {
2048:                    ClassMetaData[] subs = cmd.pcSubclasses;
2049:                    for (int i = 0; i < subs.length; i++) {
2050:                        processClassIdCol(subs[i], quiet, classIdMap);
2051:                    }
2052:                }
2053:            }
2054:
2055:            /**
2056:             * Create a new JdbcField from a JdoField and its extensions. Returns
2057:             * null if the JdoField is transactional i.e. we dont give a flying
2058:             * banana as we do not store it!
2059:             */
2060:            private JdbcField createJdbcField(FieldMetaData fmd, boolean quiet) {
2061:                try {
2062:                    switch (fmd.category) {
2063:                    case MDStatics.CATEGORY_TRANSACTIONAL:
2064:                        return null;
2065:                    case MDStatics.CATEGORY_SIMPLE:
2066:                        return createJdbcSimpleField(fmd);
2067:                    case MDStatics.CATEGORY_REF:
2068:                        return new JdbcRefField();
2069:                    case MDStatics.CATEGORY_POLYREF:
2070:                        return new JdbcPolyRefField();
2071:                    case MDStatics.CATEGORY_COLLECTION:
2072:                        return createJdbcCollectionField(fmd);
2073:                    case MDStatics.CATEGORY_ARRAY:
2074:                        return createFieldForArray(fmd);
2075:                    case MDStatics.CATEGORY_MAP:
2076:                        return new JdbcMapField();
2077:                    case MDStatics.CATEGORY_EXTERNALIZED:
2078:                        return createJdbcSerializedField(fmd);
2079:                    }
2080:                    throw BindingSupportImpl.getInstance().internal(
2081:                            "Field "
2082:                                    + fmd.name
2083:                                    + " of "
2084:                                    + fmd.classMetaData.qname
2085:                                    + " has bad category: "
2086:                                    + MDStaticUtils
2087:                                            .toCategoryString(fmd.category));
2088:                } catch (RuntimeException e) {
2089:                    fmd.addError(e, quiet);
2090:                }
2091:                return null;
2092:            }
2093:
2094:            private JdbcCollectionField createJdbcCollectionField(
2095:                    FieldMetaData fmd) {
2096:                return createJdbcField(fmd, fmd.jdoCollection == null ? null
2097:                        : fmd.jdoCollection.extensions);
2098:            }
2099:
2100:            private JdbcCollectionField createJdbcField(FieldMetaData fmd,
2101:                    JdoExtension[] exts) {
2102:                if (exts != null) {
2103:                    // look for an extension indicating that this collection is stored
2104:                    // using a foreign key in the value class instead of a link table
2105:                    // or is part of a many-to-many relationship
2106:                    JdoExtension[] a = exts;
2107:                    int n = a == null ? 0 : a.length;
2108:                    boolean gotLink = false;
2109:                    JdoExtension ie = null;
2110:                    for (int i = 0; i < n; i++) {
2111:                        JdoExtension e = a[i];
2112:                        switch (e.key) {
2113:                        case INVERSE:
2114:                        case JDBC_LINK_FOREIGN_KEY:
2115:                            if (ie != null || gotLink) {
2116:                                throw BindingSupportImpl
2117:                                        .getInstance()
2118:                                        .runtime(
2119:                                                "The "
2120:                                                        + (ie != null ? "inverse"
2121:                                                                : "jdbc-link-table")
2122:                                                        + " extension has already been specified\n"
2123:                                                        + e.getContext());
2124:                            }
2125:                            ie = e;
2126:                            break;
2127:                        case JDBC_LINK_TABLE:
2128:                            if (ie != null || gotLink) {
2129:                                throw BindingSupportImpl
2130:                                        .getInstance()
2131:                                        .runtime(
2132:                                                "The "
2133:                                                        + (ie != null ? "inverse"
2134:                                                                : "jdbc-link-table")
2135:                                                        + " extension has already been specified\n"
2136:                                                        + e.getContext());
2137:                            }
2138:                            gotLink = true;
2139:                            break;
2140:                        }
2141:                    }
2142:                    if (ie != null) {
2143:                        // see what type of field the inverse is to see if this is
2144:                        // is a many-to-many or one-to-many
2145:                        ClassMetaData ecmd = fmd.elementTypeMetaData;
2146:                        if (ecmd == null) {
2147:                            throw BindingSupportImpl.getInstance().runtime(
2148:                                    "The inverse extension may only be used for "
2149:                                            + "collections of PC instances\n"
2150:                                            + ie.getContext());
2151:                        }
2152:                        String fname = ie.getString();
2153:                        FieldMetaData f = ecmd.getFieldMetaData(fname);
2154:                        if (f == null) {
2155:                            if (fname != null
2156:                                    && (fname.equals("") || fname
2157:                                            .equals(FieldMetaData.NO_FIELD_TEXT))) {
2158:                                return new JdbcFKCollectionField();
2159:                            } else {
2160:                                throw BindingSupportImpl.getInstance().runtime(
2161:                                        "Field '" + fname + "' not found on "
2162:                                                + fmd.elementType + "\n"
2163:                                                + ie.getContext());
2164:                            }
2165:                        }
2166:                        switch (f.category) {
2167:                        case MDStatics.CATEGORY_REF:
2168:                            return new JdbcFKCollectionField();
2169:                        case MDStatics.CATEGORY_ARRAY:
2170:                        case MDStatics.CATEGORY_COLLECTION:
2171:                            return new JdbcLinkCollectionField();
2172:                        }
2173:                        throw BindingSupportImpl
2174:                                .getInstance()
2175:                                .runtime(
2176:                                        "Field '"
2177:                                                + fname
2178:                                                + "' is not a reference, collection or array\n"
2179:                                                + ie.getContext());
2180:                    }
2181:                }
2182:                return new JdbcLinkCollectionField();
2183:            }
2184:
2185:            private JdbcSimpleField createJdbcSimpleField(FieldMetaData fmd) {
2186:                JdbcSimpleField f = new JdbcSimpleField();
2187:                JdoField jdoField = fmd.jdoField;
2188:                JdoExtension[] a = jdoField == null ? null
2189:                        : jdoField.extensions;
2190:                int n = a == null ? 0 : a.length;
2191:                for (int i = 0; i < n; i++) {
2192:                    JdoExtension e = a[i];
2193:                    switch (e.key) {
2194:                    case JDBC_COLUMN:
2195:                        // handled when column is created
2196:                        break;
2197:                    default:
2198:                        if (e.isJdbc())
2199:                            MetaDataBuilder.throwUnexpectedExtension(e);
2200:                    }
2201:                }
2202:                f.col = createColumn(a, fmd.name, fmd.type);
2203:                f.col.comment = fmd.getCommentName();
2204:                if ((f.col.pk = fmd.primaryKey)
2205:                        || fmd.nullValue == MDStatics.NULL_VALUE_EXCEPTION) {
2206:                    f.col.nulls = false;
2207:                } else if (fmd.nullValue == MDStatics.NULL_VALUE_NONE) {
2208:                    f.col.nulls = true;
2209:                }
2210:                if (fmd.embeddedFakeField) {
2211:                    f.col.nulls = true;
2212:                }
2213:                f.includeForChangedLocking = f.col.equalityTest;
2214:                return f;
2215:            }
2216:
2217:            private JdbcSimpleField createJdbcSerializedField(FieldMetaData fmd) {
2218:                JdbcSimpleField f = new JdbcSimpleField();
2219:                JdoField jdoField = fmd.jdoField;
2220:                JdoExtension[] a = jdoField == null ? null
2221:                        : jdoField.extensions;
2222:                int n = a == null ? 0 : a.length;
2223:                for (int i = 0; i < n; i++) {
2224:                    JdoExtension e = a[i];
2225:                    switch (e.key) {
2226:                    case JDBC_COLUMN:
2227:                        // handled when column is created
2228:                        break;
2229:                    default:
2230:                        if (e.isJdbc())
2231:                            MetaDataBuilder.throwUnexpectedExtension(e);
2232:                    }
2233:                }
2234:                f.col = createColumn(a, fmd.name, fmd.externalizer
2235:                        .getExternalType());
2236:                f.col.comment = fmd.getCommentName();
2237:                if (fmd.nullValue == MDStatics.NULL_VALUE_EXCEPTION) {
2238:                    f.col.nulls = false;
2239:                } else if (fmd.nullValue == MDStatics.NULL_VALUE_NONE) {
2240:                    f.col.nulls = true;
2241:                }
2242:                f.includeForChangedLocking = f.col.equalityTest;
2243:                return f;
2244:            }
2245:
2246:            /**
2247:             * Create a JdbcField for an array[]. This will create a JdbcSimpleField
2248:             * if the array is embedded or a JdbcLinkCollectionField if not.
2249:             */
2250:            private JdbcField createFieldForArray(FieldMetaData fmd) {
2251:                if (fmd.embedded) {
2252:                    return createJdbcSimpleField(fmd);
2253:                } else {
2254:                    return createJdbcField(fmd, fmd.jdoArray == null ? null
2255:                            : fmd.jdoArray.extensions);
2256:                }
2257:            }
2258:
2259:            /**
2260:             * Process a pass 1 extension for a class. This ignores jdbc-datastore
2261:             * extensions as these should have already been processed. Some
2262:             * extensions are skipped to be processed later.
2263:             *
2264:             * @param jdbcElements These are the JdbcColumn's and JdbcField's that
2265:             *                     have been created so far for the class
2266:             */
2267:            private void processClassExtensionPass1(ClassMetaData cmd,
2268:                    JdoExtension e, ArrayList jdbcElements, boolean quiet) {
2269:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
2270:                ClassInfo info;
2271:                switch (e.key) {
2272:                case DATASTORE:
2273:                    // do nothing as this should have already been processed
2274:                    break;
2275:                case JDBC_INHERITANCE:
2276:                    //                if (cmd.pcSuperMetaData == null) {
2277:                    //                    RuntimeException x = BindingSupportImpl.getInstance().runtime("Class " +
2278:                    //                            cmd.qname + " does not have a " +
2279:                    //                            "persistence-capable-superclass\n" +
2280:                    //                            e.getContext());
2281:                    //                    cmd.addError(x, quiet);
2282:                    //                }
2283:                    try {
2284:                        if (e.value != null) {
2285:                            jdbcClass.inheritance = e
2286:                                    .getEnum(jdbcMDE.INHERITANCE_ENUM);
2287:                        }
2288:                        getClassInfo(cmd).inheritance = e;
2289:                    } catch (RuntimeException x) {
2290:                        cmd.addError(x, quiet);
2291:                    }
2292:                    break;
2293:                case JDBC_TABLE_NAME:
2294:                    if (jdbcClass.tableName != null) {
2295:                        RuntimeException x = BindingSupportImpl
2296:                                .getInstance()
2297:                                .runtime(
2298:                                        "Class "
2299:                                                + cmd.qname
2300:                                                + " already has a jdbc-table-name: "
2301:                                                + jdbcClass.tableName + "\n"
2302:                                                + e.getContext());
2303:                        cmd.addError(x, quiet);
2304:                    }
2305:                    jdbcClass.tableName = e.getString();
2306:                    break;
2307:                case JDBC_KEY_GENERATOR:
2308:                    if (cmd.pcSuperMetaData != null) {
2309:                        RuntimeException x = BindingSupportImpl
2310:                                .getInstance()
2311:                                .runtime(
2312:                                        "The jdbc-key-generator extension is only allowed for "
2313:                                                + "the least derived class in a heirachy\n"
2314:                                                + e.getContext());
2315:                        cmd.addError(x, quiet);
2316:                    }
2317:                    info = getClassInfo(cmd);
2318:                    if (e.value != null) {
2319:                        JdbcKeyGeneratorFactory f = findKeyGenFactory(e);
2320:                        if (info.keyGenFactory != f) {
2321:                            info.keyGenFactory = f;
2322:                            info.keyGenFactoryArgs = f.createArgsBean();
2323:                        }
2324:                    } else if (info.keyGenFactory == null) {
2325:                        RuntimeException x = BindingSupportImpl
2326:                                .getInstance()
2327:                                .runtime(
2328:                                        "The jdbc-key-generator extension must specify a factory "
2329:                                                + "for application identity classes\n"
2330:                                                + e.getContext());
2331:                        cmd.addError(x, quiet);
2332:                    }
2333:                    BeanUtils.setProperties(info.keyGenFactoryArgs, e
2334:                            .getPropertyMap());
2335:                    break;
2336:                case JDBC_INDEX:
2337:                    try {
2338:                        info = getClassInfo(cmd);
2339:                        info.indexExts.add(e);
2340:                    } catch (RuntimeException x) {
2341:                        cmd.addError(x, quiet);
2342:                    }
2343:                    break;
2344:                case JDBC_OPTIMISTIC_LOCKING:
2345:                    try {
2346:                        processClassOptimisticLocking(e, jdbcClass, cmd, quiet);
2347:                    } catch (RuntimeException x) {
2348:                        cmd.addError(x, quiet);
2349:                    }
2350:                    break;
2351:                case JDBC_CLASS_ID:
2352:                    try {
2353:                        processJdbcClassIdExtension(cmd, e, jdbcClass);
2354:                    } catch (RuntimeException x) {
2355:                        cmd.addError(x, quiet);
2356:                    }
2357:                    break;
2358:                case JDBC_COLUMN:
2359:                    try {
2360:                        processClassColumnExtension(e, cmd, jdbcElements);
2361:                    } catch (RuntimeException x) {
2362:                        cmd.addError(x, quiet);
2363:                    }
2364:                    break;
2365:                case JDBC_PRIMARY_KEY:
2366:                    try {
2367:                        processClassPrimaryKeyExtension(e, cmd, jdbcElements);
2368:                    } catch (RuntimeException x) {
2369:                        cmd.addError(x, quiet);
2370:                    }
2371:                    break;
2372:                case JDBC_PK_FK_CONSTRAINT_NAME:
2373:                    info = getClassInfo(cmd);
2374:                    if (info.pkFkConstraintName != null) {
2375:                        RuntimeException x = BindingSupportImpl.getInstance()
2376:                                .runtime(
2377:                                        "The jdbc-pk-fk-constraint extension may only appear once\n"
2378:                                                + e.getContext());
2379:                        cmd.addError(x, quiet);
2380:                    }
2381:                    info.pkFkConstraintName = e.getString();
2382:                    break;
2383:                case JDBC_USE_JOIN:
2384:                    try {
2385:                        jdbcClass.useJoin = e.getEnum(jdbcMDE.USE_JOIN_ENUM);
2386:                    } catch (RuntimeException x) {
2387:                        cmd.addError(x, quiet);
2388:                    }
2389:                    break;
2390:                case JDBC_DO_NOT_CREATE_TABLE:
2391:                    try {
2392:                        jdbcClass.doNotCreateTable = e.getBoolean();
2393:                    } catch (RuntimeException x) {
2394:                        cmd.addError(x, quiet);
2395:                    }
2396:                    break;
2397:                default:
2398:                    if (e.isJdbc())
2399:                        MetaDataBuilder.throwUnexpectedExtension(e);
2400:                }
2401:            }
2402:
2403:            private void processJdbcClassIdExtension(ClassMetaData cmd,
2404:                    JdoExtension e, JdbcClass jdbcClass) {
2405:                ClassInfo info;
2406:                info = getClassInfo(cmd);
2407:                if (info.classIdExt != null) {
2408:                    throw BindingSupportImpl.getInstance().invalidOperation(
2409:                            "The jdbc-class-id extension may "
2410:                                    + "only be specified once\n"
2411:                                    + e.getContext());
2412:                }
2413:                info.classIdExt = e;
2414:                if (e.value != null) {
2415:                    info.noClassIdCol = false;
2416:                    if (e.isNoValue()) {
2417:                        if (cmd.pcSuperMetaData != null) {
2418:                            throw BindingSupportImpl
2419:                                    .getInstance()
2420:                                    .invalidOperation(
2421:                                            JdoExtension.NO_VALUE
2422:                                                    + " is only valid "
2423:                                                    + "for the least derived class in the "
2424:                                                    + "heircachy:\n"
2425:                                                    + e.getContext());
2426:                        }
2427:                        info.noClassIdCol = true;
2428:                    } else if (JdoExtension.NAME_VALUE.equals(e.value)) {
2429:                        jdbcClass.jdbcClassId = cmd.jdoClass.name;
2430:                    } else if (JdoExtension.FULLNAME_VALUE.equals(e.value)) {
2431:                        jdbcClass.jdbcClassId = cmd.qname;
2432:                    } else {
2433:                        jdbcClass.jdbcClassId = e.value;
2434:                    }
2435:                }
2436:                if (e.nested != null) {
2437:                    if (cmd.pcSuperMetaData != null) {
2438:                        throw BindingSupportImpl
2439:                                .getInstance()
2440:                                .runtime(
2441:                                        "The jdbc-class-id extension may "
2442:                                                + "only define a column for the least derived class in the "
2443:                                                + "heirachy\n" + e.getContext());
2444:                    }
2445:                }
2446:            }
2447:
2448:            private void processClassOptimisticLocking(JdoExtension e,
2449:                    JdbcClass jdbcClass, ClassMetaData cmd, boolean quiet) {
2450:                if (cmd.pcSuperMetaData != null) {
2451:                    RuntimeException x = BindingSupportImpl
2452:                            .getInstance()
2453:                            .runtime(
2454:                                    "The jdbc-optimistic-locking "
2455:                                            + "option may only be specified for the least derived class "
2456:                                            + "in a heirachy\n"
2457:                                            + e.getContext());
2458:                    cmd.addError(x, quiet);
2459:                }
2460:                if (e.value != null) {
2461:                    try {
2462:                        jdbcClass.optimisticLocking = e
2463:                                .getEnum(jdbcMDE.OPTIMISTIC_LOCKING_ENUM);
2464:                    } catch (RuntimeException x) {
2465:                        cmd.addError(x, quiet);
2466:                    }
2467:                }
2468:                getClassInfo(cmd).optimisticLockingExt = e;
2469:            }
2470:
2471:            private void processClassColumnExtension(JdoExtension e,
2472:                    ClassMetaData cmd, ArrayList jdbcElements) {
2473:                JdbcColumn col = createColumn(e.nested, CLASS_ID_FIELDNAME,
2474:                        Integer.TYPE);
2475:                JdbcSimpleField f = new JdbcSimpleField();
2476:                f.fake = true;
2477:                f.col = col;
2478:                FieldMetaData fmd = f.fmd = new FieldMetaData();
2479:                fmd.fake = true;
2480:                fmd.category = MDStatics.CATEGORY_SIMPLE;
2481:                fmd.classMetaData = cmd;
2482:                fmd.defaultFetchGroup = true;
2483:                fmd.storeField = f;
2484:                fmd.name = "jdo" + jdbcElements.size();
2485:                fmd.persistenceModifier = MDStatics.PERSISTENCE_MODIFIER_PERSISTENT;
2486:                fmd.setType(col.javaType);
2487:                jdbcElements.add(f);
2488:            }
2489:
2490:            private void processClassPrimaryKeyExtension(JdoExtension e,
2491:                    ClassMetaData cmd, ArrayList jdbcElements) {
2492:                if (cmd.identityType != MDStatics.IDENTITY_TYPE_DATASTORE) {
2493:                    throw BindingSupportImpl.getInstance().runtime(
2494:                            "jdbc-primary-key only allowed for classes "
2495:                                    + "with identity-type 'datastore'\n"
2496:                                    + e.getContext());
2497:                }
2498:
2499:                ClassInfo info;
2500:                JdoExtension[] a = e.nested;
2501:                int n = a == null ? 0 : a.length;
2502:                for (int i = 0; i < n; i++) {
2503:                    JdoExtension f = a[i];
2504:                    switch (f.key) {
2505:                    case JDBC_COLUMN:
2506:                        // handled when column is created
2507:                        break;
2508:                    case JDBC_CONSTRAINT:
2509:                        info = getClassInfo(cmd);
2510:                        if (info.pkConstraintName != null) {
2511:                            throw BindingSupportImpl.getInstance().runtime(
2512:                                    "The jdbc-constraint extension may only appear once\n"
2513:                                            + e.getContext());
2514:                        }
2515:                        info.pkConstraintName = e.getString();
2516:                        break;
2517:                    default:
2518:                        if (e.isJdbc())
2519:                            MetaDataBuilder.throwUnexpectedExtension(e);
2520:                    }
2521:                }
2522:
2523:                JdbcColumn col = createColumn(a, DATASTORE_PK_FIELDNAME,
2524:                        Integer.TYPE);
2525:                col.pk = true;
2526:                col.nulls = false;
2527:                jdbcElements.add(col);
2528:            }
2529:
2530:            /**
2531:             * Find the factory specified in a jdbc-key-generator extension. If the
2532:             * factory is new an instance is created and stored for future access.
2533:             */
2534:            private JdbcKeyGeneratorFactory findKeyGenFactory(JdoExtension e) {
2535:                String fname = e.getString();
2536:                try {
2537:                    return keyGenRegistry.getFactory(fname);
2538:                } catch (Exception x) {
2539:                    throw BindingSupportImpl.getInstance().runtime(
2540:                            x.getMessage() + "\n" + e.getContext(), x);
2541:                }
2542:            }
2543:
2544:            /**
2545:             * Create a JdbcConverterFactory instance from an extension.
2546:             */
2547:            private JdbcConverterFactory createJdbcConverterFactory(
2548:                    JdoExtension e) {
2549:                try {
2550:                    return converterRegistry.getFactory(e.getString());
2551:                } catch (Exception x) {
2552:                    throw BindingSupportImpl.getInstance().runtime(
2553:                            "Unable to create JdbcConverterFactory\n"
2554:                                    + e.getContext(), x);
2555:                }
2556:            }
2557:
2558:            /**
2559:             * Create a column from an optional array of extensions, an optional
2560:             * fieldName and a base column. The properties of the base column are
2561:             * the defaults. If nested is not null then it is searched for a
2562:             * jdbc-column extension with a value matching the database
2563:             * property of the store. If none is found then a jdbc-column extension
2564:             * with no value is used. If it contains no jdbc-column extensions then
2565:             * it is ignored. If the jdbc-type has been set in the extension then
2566:             * it is used to provide the defaults, not the column.
2567:             */
2568:            public JdbcColumn createColumn(JdoExtension[] nested,
2569:                    JdbcColumn base) {
2570:
2571:                // look for a jdbc-column extension matching our db or with no db
2572:                nested = findMatchingJdbcColumn(nested);
2573:
2574:                // copy the base column and use the mapping to change properties
2575:                JdbcColumn c = base.copy();
2576:                if (nested != null) {
2577:                    JdbcJavaTypeMapping m = createFieldMapping(nested);
2578:                    mappingResolver.fillMappingForJdbcType(m);
2579:                    c.updateFrom(m, mappingResolver);
2580:                    updateColumnName(nested, c);
2581:                    updateConverter(nested, c);
2582:                }
2583:                return c;
2584:            }
2585:
2586:            /**
2587:             * Create a column from an optional array of extensions, an optional
2588:             * fieldName and an optional javaType. If nested is not null then it is
2589:             * searched for a jdbc-column extension with a value matching the database
2590:             * property of the store. If none is found then a jdbc-column extension
2591:             * with no value is used. If it contains no jdbc-column extensions then
2592:             * it is ignored.
2593:             */
2594:            public JdbcColumn createColumn(JdoExtension[] nested,
2595:                    String fieldName, Class javaType) {
2596:
2597:                // look for a jdbc-column extension matching our db or with no db
2598:                nested = findMatchingJdbcColumn(nested);
2599:
2600:                // create a fully resolved mapping and use this to make the column
2601:                JdbcJavaTypeMapping m = createFieldMapping(nested);
2602:                m = mappingResolver.resolveMapping(m, fieldName, javaType);
2603:                JdbcColumn c = new JdbcColumn(m, mappingResolver);
2604:                updateColumnName(nested, c);
2605:                updateConverter(nested, c);
2606:                c.comment = fieldName;
2607:                return c;
2608:            }
2609:
2610:            /**
2611:             * Set the converter (if any).
2612:             */
2613:            private void updateConverter(JdoExtension[] nested, JdbcColumn c) {
2614:                if (nested != null) {
2615:                    boolean done = false;
2616:                    int n = nested.length;
2617:                    for (int i = 0; i < n; i++) {
2618:                        JdoExtension e = nested[i];
2619:                        if (e.key == JDBC_CONVERTER) {
2620:                            if (done) {
2621:                                throw BindingSupportImpl.getInstance().runtime(
2622:                                        "jdbc-converter extension has already been used\n"
2623:                                                + e.getContext());
2624:                            }
2625:                            JdbcConverterFactory f = createJdbcConverterFactory(e);
2626:                            HashMap p = e.getPropertyMap();
2627:                            try {
2628:                                c.converter = f.createJdbcConverter(c, p,
2629:                                        mappingResolver);
2630:                            } catch (IllegalArgumentException x) {
2631:                                throw BindingSupportImpl.getInstance().runtime(
2632:                                        "Unable to create JdbcConverter\n"
2633:                                                + e.getContext(), x);
2634:                            }
2635:                            done = true;
2636:                        }
2637:                    }
2638:                }
2639:            }
2640:
2641:            /**
2642:             * Set the column name (if any).
2643:             */
2644:            private void updateColumnName(JdoExtension[] nested, JdbcColumn c) {
2645:                if (nested != null) {
2646:                    int n = nested.length;
2647:                    for (int i = 0; i < n; i++) {
2648:                        JdoExtension e = nested[i];
2649:                        if (e.key != JDBC_COLUMN_NAME)
2650:                            continue;
2651:                        if (c.name != null) {
2652:                            throw BindingSupportImpl.getInstance().runtime(
2653:                                    "Only one jdbc-column-name extension is allowed\n"
2654:                                            + e.getContext());
2655:                        }
2656:                        c.name = e.getString();
2657:                    }
2658:                }
2659:            }
2660:
2661:            /**
2662:             * If nested is not null then it is searched for a jdbc-column extension
2663:             * with a value matching the database property of the store. If none is
2664:             * found then a jdbc-column extension with no value is used. If it
2665:             * contains no jdbc-column extensions then it is ignored.
2666:             */
2667:            private JdoExtension[] findMatchingJdbcColumn(JdoExtension[] nested) {
2668:                if (nested != null) {
2669:                    JdoExtension matchGeneral = null;
2670:                    JdoExtension matchSpecific = null;
2671:                    String sdb = sqlDriver.getName();
2672:                    int n = nested.length;
2673:                    for (int i = 0; i < n; i++) {
2674:                        JdoExtension e = nested[i];
2675:                        if (e.key != JDBC_COLUMN)
2676:                            continue;
2677:                        String db = e.value;
2678:                        if (db == null) {
2679:                            if (matchGeneral != null) {
2680:                                throw BindingSupportImpl.getInstance().runtime(
2681:                                        "Only one all databases jdbc-column extension is allowed\n"
2682:                                                + e.getContext());
2683:                            }
2684:                            matchGeneral = e;
2685:                        } else if (db.equals(sdb)) {
2686:                            if (matchSpecific != null) {
2687:                                throw BindingSupportImpl.getInstance().runtime(
2688:                                        "Only one jdbc-column extension is allowed per database\n"
2689:                                                + e.getContext());
2690:                            }
2691:                            matchSpecific = e;
2692:                        }
2693:                    }
2694:                    if (matchSpecific != null) {
2695:                        nested = matchSpecific.nested;
2696:                    } else if (matchGeneral != null) {
2697:                        nested = matchGeneral.nested;
2698:                    } else {
2699:                        nested = null;
2700:                    }
2701:                }
2702:                return nested;
2703:            }
2704:
2705:            /**
2706:             * Create a field mapping from an array of extensions.
2707:             *
2708:             * @param nested Nested extensions (may be null)
2709:             */
2710:            private JdbcJavaTypeMapping createFieldMapping(JdoExtension[] nested) {
2711:                JdbcJavaTypeMapping m = new JdbcJavaTypeMapping();
2712:                if (nested == null)
2713:                    return m;
2714:                int n = nested.length;
2715:                for (int i = 0; i < n; i++) {
2716:                    JdoExtension e = nested[i];
2717:                    switch (e.key) {
2718:                    case JDBC_COLUMN_NAME:
2719:                        if (m.getColumnName() != null) {
2720:                            throw BindingSupportImpl.getInstance().runtime(
2721:                                    "jdbc-column-name has already been set\n"
2722:                                            + e.getContext());
2723:                        }
2724:                        m.setColumnName(e.getString());
2725:                        break;
2726:                    case JDBC_TYPE:
2727:                        if (m.getJdbcType() != 0) {
2728:                            throw BindingSupportImpl.getInstance().runtime(
2729:                                    "jdbc-type has already been set\n"
2730:                                            + e.getContext());
2731:                        }
2732:                        m.setJdbcType(getJdbcType(e));
2733:                        break;
2734:                    case JDBC_SQL_TYPE:
2735:                        if (m.getSqlType() != null) {
2736:                            throw BindingSupportImpl.getInstance().runtime(
2737:                                    "jdbc-sql-type has already been set\n"
2738:                                            + e.getContext());
2739:                        }
2740:                        m.setSqlType(e.getString());
2741:                        break;
2742:                    case JDBC_LENGTH:
2743:                        if (m.getLength() >= 0) {
2744:                            throw BindingSupportImpl.getInstance().runtime(
2745:                                    "jdbc-length has already been set\n"
2746:                                            + e.getContext());
2747:                        }
2748:                        m.setLength(e.getInt());
2749:                        break;
2750:                    case JDBC_SCALE:
2751:                        if (m.getScale() >= 0) {
2752:                            throw BindingSupportImpl.getInstance().runtime(
2753:                                    "jdbc-scale has already been set\n"
2754:                                            + e.getContext());
2755:                        }
2756:                        m.setScale(e.getInt());
2757:                        break;
2758:                    case JDBC_NULLS:
2759:                        if (m.getNulls() != JdbcJavaTypeMapping.NOT_SET) {
2760:                            throw BindingSupportImpl.getInstance().runtime(
2761:                                    "jdbc-nulls has already been set\n"
2762:                                            + e.getContext());
2763:                        }
2764:                        m.setNulls(e.getBoolean());
2765:                        break;
2766:                    case JDBC_SHARED:
2767:                        // ignore - shared columns are now figured out automatically
2768:                        break;
2769:                    case JDBC_JAVA_TYPE:
2770:                        if (m.getJavaType() != null) {
2771:                            throw BindingSupportImpl.getInstance().runtime(
2772:                                    "jdbc-java-type has already been set\n"
2773:                                            + e.getContext());
2774:                        }
2775:                        m.setJavaType(e.getType(loader));
2776:                        break;
2777:                    case JDBC_CONVERTER:
2778:                        // handled once the column has been created
2779:                        break;
2780:                    default:
2781:                        if (e.isJdbc())
2782:                            MetaDataBuilder.throwUnexpectedExtension(e);
2783:                        break;
2784:                    }
2785:                }
2786:                return m;
2787:            }
2788:
2789:            /**
2790:             * Get the value of an extension that must be a JDBC type name.
2791:             *
2792:             * @see java.sql.Types
2793:             */
2794:            public int getJdbcType(JdoExtension e) {
2795:                try {
2796:                    return JdbcTypes.parse(e.getString());
2797:                } catch (IllegalArgumentException x) {
2798:                    throw BindingSupportImpl.getInstance().runtime(
2799:                            x.getMessage() + "\n" + e.getContext());
2800:                }
2801:            }
2802:
2803:            public ModelMetaData getJmd() {
2804:                return jmd;
2805:            }
2806:
2807:            public SqlDriver getSqlDriver() {
2808:                return sqlDriver;
2809:            }
2810:
2811:            public JdbcMappingResolver getMappingResolver() {
2812:                return mappingResolver;
2813:            }
2814:
2815:            protected void setMasterDetailFlags(ClassMetaData[] classes) {
2816:                if (Debug.DEBUG) {
2817:                    System.out.println("MDB-JDBC: Setting master detail flags");
2818:                }
2819:                int clen = classes.length;
2820:                for (int i = 0; i < clen; i++) {
2821:                    ClassMetaData cmd = classes[i];
2822:                    if (cmd.stateFields == null)
2823:                        continue; // possible if prev error
2824:                    for (int j = 0; j < cmd.stateFields.length; j++) {
2825:                        FieldMetaData fmd = cmd.stateFields[j];
2826:                        switch (fmd.category) {
2827:                        case MDStatics.CATEGORY_REF:
2828:                            JdbcField jdbcField = (JdbcField) fmd.storeField;
2829:                            if (jdbcField != null) { // possible if prev error
2830:                                JdbcFKCollectionField masterField = ((JdbcRefField) jdbcField).masterCollectionField;
2831:                                if (masterField != null) {
2832:                                    fmd.inverseFieldMetaData = masterField.fmd;
2833:                                    fmd.isDetail = true;
2834:                                    fmd.managed = masterField.fmd.managed;
2835:                                }
2836:                            }
2837:                            break;
2838:                        case MDStatics.CATEGORY_COLLECTION:
2839:                            if (fmd.storeField instanceof  JdbcFKCollectionField) {
2840:                                fmd.inverseFieldMetaData = ((JdbcFKCollectionField) fmd.storeField).fkField.fmd;
2841:                                fmd.isMaster = true;
2842:                            }
2843:                            break;
2844:                        }
2845:                    }
2846:                }
2847:            }
2848:
2849:            protected void calcSuperCounts(ClassMetaData[] classes) {
2850:                super .calcSuperCounts(classes);
2851:                // find all the references that are being used to complete
2852:                // collections mapped using a foreign key
2853:                for (int j = 0; j < classes.length; j++) {
2854:                    ClassMetaData cmd = classes[j];
2855:                    if (cmd == null || cmd.stateFields == null) {
2856:                        continue;
2857:                    }
2858:                    int[] a = new int[cmd.stateFields.length];
2859:                    int c = 0;
2860:                    for (int i = cmd.stateFields.length - 1; i >= 0; i--) {
2861:                        FieldMetaData f = cmd.stateFields[i];
2862:                        if (f.storeField instanceof  JdbcRefField) {
2863:                            JdbcRefField rf = (JdbcRefField) f.storeField;
2864:                            if (rf.masterCollectionField != null) {
2865:                                a[c++] = i;
2866:                            }
2867:                        }
2868:                    }
2869:                    if (c > 0) {
2870:                        int[] b = new int[c];
2871:                        System.arraycopy(a, 0, b, 0, c);
2872:                        cmd.fkCollectionRefStateFieldNos = b;
2873:                    } else {
2874:                        cmd.fkCollectionRefStateFieldNos = null;
2875:                    }
2876:                }
2877:            }
2878:
2879:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.