Source Code Cross Referenced for MetaDataBuilder.java in  » Testing » PolePosition-0.20 » com » versant » core » metadata » 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.metadata 
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.metadata;
0012:
0013:        import com.versant.core.common.Debug;
0014:        import com.versant.core.common.config.ConfigInfo;
0015:        import com.versant.core.jdo.QueryDetails;
0016:        import com.versant.core.jdo.sco.VersantSCOFactoryRegistry;
0017:        import com.versant.core.metadata.parser.*;
0018:        import com.versant.core.jdo.query.ParseException;
0019:        import com.versant.core.jdo.query.QueryParser;
0020:        import com.versant.core.jdo.externalizer.Externalizer;
0021:        import com.versant.core.jdo.externalizer.SerializedExternalizer;
0022:        import com.versant.core.jdo.externalizer.TypeAsBytesExternalizer;
0023:        import com.versant.core.jdo.externalizer.TypeAsStringExternalizer;
0024:        import com.versant.core.util.classhelper.ClassHelper;
0025:        import com.versant.core.util.BeanUtils;
0026:        import com.versant.core.util.IntArray;
0027:
0028:        import java.io.Serializable;
0029:        import java.lang.reflect.*;
0030:        import java.util.*;
0031:
0032:        import com.versant.core.common.BindingSupportImpl;
0033:
0034:        /**
0035:         * This will parse one or more .jdo files and load and analyze the persistent
0036:         * classes to produce basic meta data. There are different subclasses for
0037:         * different StorageManager's.
0038:         */
0039:        public class MetaDataBuilder implements  MDStatics {
0040:
0041:            protected final ConfigInfo config;
0042:            protected final ClassLoader loader;
0043:            protected final boolean quiet;
0044:            protected final ModelMetaData jmd;
0045:
0046:            private MetaDataPreProcessor metaDataPreProcessor;
0047:
0048:            private final MetaDataEnums MDE = new MetaDataEnums();
0049:
0050:            protected final MetaDataUtils mdutils = new MetaDataUtils();
0051:            protected final VersantSCOFactoryRegistry scoFactoryRegistry;
0052:
0053:            private Map appIdUniqueMap = new HashMap();
0054:            private Map externalizerMap = new HashMap();
0055:
0056:            private PackageMetaData[] packageMetaData;
0057:            private HashMap classMap = new HashMap(); //  Class -> ClassMetaData
0058:            private HashMap classInfoMap = new HashMap(); //  Class -> ClassInfo
0059:            private HashMap interfaceMap = new HashMap(); // Class -> InterfaceMetaData
0060:            private HashMap classAndInterfaceMap = new HashMap();
0061:            // Class -> ClassMetaData/InterfaceMetaData
0062:
0063:            private final FetchGroupBuilder fetchGroupBuilder;
0064:            private final QueryParser queryParser;
0065:            private static final String ARRAY_SUFFIX = "[]";
0066:
0067:            /**
0068:             * Info extracted from package extensions. These form defaults that
0069:             * apply to all classes in the package unless overridden at class level.
0070:             */
0071:            private static class PackageMetaData {
0072:
0073:                public String nameWithDot;
0074:                public JdoPackage jdoPackage;
0075:            }
0076:
0077:            /**
0078:             * Info extracted from class extensions that is only needed during
0079:             * meta data generation.
0080:             */
0081:            private static class ClassInfo {
0082:
0083:                public boolean refsInDefaultFetchGroup;
0084:                public JdoClass jdoClass;
0085:                public ArrayList horizontalFields;
0086:            }
0087:
0088:            public MetaDataBuilder(ConfigInfo config, ClassLoader loader,
0089:                    boolean quiet) {
0090:                this .config = config;
0091:                this .loader = loader;
0092:                this .quiet = quiet;
0093:                jmd = new ModelMetaData();
0094:                jmd.testing = config.testing;
0095:                fetchGroupBuilder = createFetchGroupBuilder();
0096:                queryParser = new QueryParser(jmd);
0097:                scoFactoryRegistry = new VersantSCOFactoryRegistry(
0098:                        config.scoFactoryRegistryMappings, loader);
0099:
0100:                if (config.metaDataPreProcessor == null)
0101:                    config.metaDataPreProcessor = EJB_JDBC_PRE_PROCESSOR;
0102:
0103:                if (config.metaDataPreProcessor != null) {
0104:                    try {
0105:                        Class cls = loadClass(config.metaDataPreProcessor);
0106:                        metaDataPreProcessor = (MetaDataPreProcessor) cls
0107:                                .getConstructor(
0108:                                        new Class[] { ClassLoader.class,
0109:                                                MetaDataUtils.class })
0110:                                .newInstance(new Object[] { loader, mdutils });
0111:                    } catch (Throwable e) {
0112:                        System.out
0113:                                .println("Unable to load 'metaDataPreProcessor' class '"
0114:                                        + config.metaDataPreProcessor + "'");
0115:                    }
0116:                }
0117:            }
0118:
0119:            protected FetchGroupBuilder createFetchGroupBuilder() {
0120:                return new FetchGroupBuilder(jmd,
0121:                        isSendCurrentForFGWithSecFields(),
0122:                        isReadObjectBeforeWrite());
0123:            }
0124:
0125:            public FetchGroupBuilder getFetchGroupBuilder() {
0126:                return fetchGroupBuilder;
0127:            }
0128:
0129:            /**
0130:             * Create meta data for already parsed .jdo meta data.
0131:             */
0132:            public ModelMetaData buildMetaData(JdoRoot[] roots) {
0133:
0134:                // populate the externalizer map
0135:                fillExternalizerMap();
0136:
0137:                // combine all the meta data into a single structure
0138:                JdoRoot jdoRoot = buildSingleJdoRoot(roots);
0139:
0140:                // pull out some package level defaults
0141:                int n = jdoRoot.packages.length;
0142:                packageMetaData = new PackageMetaData[n];
0143:                for (int i = 0; i < n; i++) {
0144:                    packageMetaData[i] = createPackageMetaData(jdoRoot.packages[i]);
0145:                }
0146:
0147:                // create initial meta data for all classes
0148:                if (Debug.DEBUG) {
0149:                    System.out
0150:                            .println("MDB: Creating initial meta data for all classes and interfaces");
0151:                }
0152:
0153:                ClassMetaData[] classes = jmd.classes = new ClassMetaData[jmd.classResourceMap
0154:                        .size()];
0155:                for (int i = 0, c = 0; i < packageMetaData.length; i++) {
0156:                    PackageMetaData pmd = packageMetaData[i];
0157:                    JdoClass[] ca = pmd.jdoPackage.classes;
0158:                    for (int j = 0; j < ca.length; j++) {
0159:                        if (metaDataPreProcessor != null)
0160:                            metaDataPreProcessor.process(ca[j]);
0161:                        ClassMetaData cmd = createMetaData(pmd, ca[j], quiet);
0162:                        classes[c++] = cmd;
0163:                        classMap.put(cmd.cls, cmd);
0164:                    }
0165:                    JdoExtension[] extensions = pmd.jdoPackage.extensions;
0166:                    if (extensions != null) {
0167:                        for (int j = 0; j < extensions.length; j++) {
0168:                            JdoExtension e = extensions[j];
0169:                            if (e.key == JdoExtensionKeys.INTERFACE) {
0170:                                InterfaceMetaData imd = createInterfaceMetaData(
0171:                                        pmd, e);
0172:                                interfaceMap.put(imd.cls, imd);
0173:                            }
0174:                        }
0175:                    }
0176:                }
0177:                jmd.buildObjectIdClassMap();
0178:                jmd.buildAbstractSchemaNameMap();
0179:                classAndInterfaceMap.putAll(classMap);
0180:                classAndInterfaceMap.putAll(interfaceMap);
0181:
0182:                // sort the classes by name and generate classId's - the name sort
0183:                // ensures that the classIds are allocated deterministicly
0184:                if (Debug.DEBUG) {
0185:                    System.out
0186:                            .println("MDB: Sorting classes by name and generating classIds");
0187:                }
0188:                Arrays.sort(classes, new Comparator() {
0189:                    public int compare(Object aa, Object bb) {
0190:                        ClassMetaData a = (ClassMetaData) aa;
0191:                        ClassMetaData b = (ClassMetaData) bb;
0192:                        return a.qname.compareTo(b.qname);
0193:                    }
0194:                });
0195:                int clen = classes.length;
0196:                for (int i = 0; i < clen; i++) {
0197:                    ClassMetaData c = classes[i];
0198:                    c.setClassId(mdutils.generateClassId(c.qname));
0199:                }
0200:
0201:                // fill in the pcClassMetaData field for all classes
0202:                if (Debug.DEBUG)
0203:                    System.out.println("MDB: Filling pcClassMetaData");
0204:                for (int i = 0; i < clen; i++) {
0205:                    ClassMetaData c = classes[i];
0206:                    Class pcs = c.pcSuperClass;
0207:                    if (pcs == null)
0208:                        continue;
0209:                    c.pcSuperMetaData = (ClassMetaData) classMap.get(pcs);
0210:                    if (c.pcSuperMetaData == null) {
0211:                        RuntimeException x = BindingSupportImpl.getInstance()
0212:                                .runtime(
0213:                                        "persistence-capable-superclass not declared in meta data: "
0214:                                                + pcs.getName() + "\n"
0215:                                                + c.jdoClass.getContext());
0216:                        c.addError(x, quiet);
0217:                    } else if (c.pcSuperMetaData.horizontal) {
0218:                        c.horizontalCMD = c.pcSuperMetaData;
0219:                        c.pcSuperMetaData = null;
0220:                    }
0221:                }
0222:
0223:                // build the pcSubclasses arrays
0224:                if (Debug.DEBUG) {
0225:                    System.out.println("MDB: Building pcSubclasses arrays");
0226:                }
0227:                ArrayList a = new ArrayList();
0228:                for (int i = 0; i < clen; i++) {
0229:                    ClassMetaData c = classes[i];
0230:                    a.clear();
0231:                    for (int j = 0; j < clen; j++) {
0232:                        ClassMetaData sc = classes[j];
0233:                        if (sc.pcSuperMetaData == c)
0234:                            a.add(sc);
0235:                    }
0236:                    int len = a.size();
0237:                    if (len > 0) {
0238:                        c.pcSubclasses = new ClassMetaData[len];
0239:                        a.toArray(c.pcSubclasses);
0240:                    }
0241:                }
0242:
0243:                // fill the pcHeirachy field for all classes and copy the identityType
0244:                // down the heirachy
0245:                if (Debug.DEBUG) {
0246:                    System.out
0247:                            .println("MDB: Filling pcHeirachy field + copying identity type down");
0248:                }
0249:                for (int i = 0; i < clen; i++) {
0250:                    ClassMetaData cmd = classes[i];
0251:                    if (cmd.pcSuperMetaData == null) {
0252:                        cmd.calcPcHeirachy();
0253:                        if (config.hyperdrive) {
0254:                            cmd.oidClassName = MDStatics.GEN_OID_START
0255:                                    + cmd.qname.replace('.', '_').replace('$',
0256:                                            '_');
0257:                        }
0258:                    }
0259:                }
0260:
0261:                // name the hyperdrive OID and State classes
0262:                if (config.hyperdrive) {
0263:                    for (int i = 0; i < clen; i++) {
0264:                        ClassMetaData cmd = classes[i];
0265:                        if (cmd.pcSuperMetaData != null) {
0266:                            cmd.oidClassName = cmd.top.oidClassName;
0267:                        }
0268:                        cmd.stateClassName = MDStatics.GEN_STATE_START
0269:                                + cmd.qname.replace('.', '_').replace('$', '_');
0270:                    }
0271:                }
0272:
0273:                // create meta data for all fields of all classes
0274:                if (Debug.DEBUG)
0275:                    System.out.println("MDB: Creating field meta data");
0276:                ClassMetaData[] ca = jmd.classes;
0277:                for (int j = 0; j < ca.length; j++) {
0278:                    ClassMetaData cmd = ca[j];
0279:                    try {
0280:                        createFieldMetaData(cmd, quiet);
0281:                    } catch (RuntimeException e) {
0282:                        cmd.addError(e, quiet);
0283:                    }
0284:                }
0285:
0286:                doEmbedded(ca);
0287:                doHorizontal(ca);
0288:
0289:                // extract all the primary key fields for all classes
0290:                if (Debug.DEBUG) {
0291:                    System.out.println("MDB: Extracting primary key fields");
0292:                }
0293:                for (int i = 0; i < clen; i++) {
0294:                    extractPrimaryKeyFields(classes[i], quiet);
0295:                }
0296:
0297:                // sort the classes array by classId so we can do a binary search
0298:                // and fill the index fields on all classes
0299:                if (Debug.DEBUG)
0300:                    System.out.println("MDB: Sorting classes by classId");
0301:                Arrays.sort(jmd.classes);
0302:                for (int i = 0; i < clen; i++)
0303:                    classes[i].index = i;
0304:
0305:                // call init1 on all our DataStore's - they may add additional store
0306:                // specific meta data at this time
0307:                if (Debug.DEBUG) {
0308:                    System.out.println("MDB: Calling preBuildFetchGroupsHook");
0309:                }
0310:                preBuildFetchGroupsHook();
0311:
0312:                // create all the fetch groups
0313:                if (Debug.DEBUG)
0314:                    System.out.println("MDB: Creating fetch groups");
0315:                fetchGroupBuilder.buildFetchGroups(quiet);
0316:
0317:                calcSuperCounts(classes);
0318:
0319:                // resolve all ordering fields
0320:                if (Debug.DEBUG) {
0321:                    System.out
0322:                            .println("MDB: Resolving collection field ordering");
0323:                }
0324:                for (int i = 0; i < clen; i++)
0325:                    resolveOrdering(classes[i], quiet);
0326:
0327:                // give all DataStore's a chance to do extra stuff now that
0328:                // superFieldCount and superFetchGroupCount are filled in
0329:                if (Debug.DEBUG) {
0330:                    System.out.println("MDB: Calling postAllFieldsCreatedHook");
0331:                }
0332:                postAllFieldsCreatedHook();
0333:
0334:                // fill in the maxFieldsLength value
0335:                if (Debug.DEBUG) {
0336:                    System.out.println("MDB: Calculating maxFieldsLength");
0337:                }
0338:                int max = 0;
0339:                for (int i = 0; i < clen; i++) {
0340:                    ClassMetaData c = classes[i];
0341:                    int len = c.stateFields == null ? 0 : c.stateFields.length;
0342:                    if (len > max)
0343:                        max = len;
0344:                }
0345:                jmd.maxFieldsLength = max;
0346:
0347:                // collect all the pass 2 fields for each class
0348:                if (Debug.DEBUG) {
0349:                    System.out
0350:                            .println("MDB: Creating pass2Fields[] for each class");
0351:                }
0352:                IntArray ia = new IntArray();
0353:                for (int i = 0; i < clen; i++) {
0354:                    ClassMetaData cmd = classes[i];
0355:                    ia.clear();
0356:                    FieldMetaData[] fields = cmd.fields;
0357:                    if (fields == null)
0358:                        continue; // possible if previous errors
0359:                    int fc = fields.length;
0360:                    for (int j = 0; j < fc; j++) {
0361:                        FieldMetaData fmd = fields[j];
0362:                        if (fmd.secondaryField)
0363:                            ia.add(fmd.fieldNo);
0364:                    }
0365:                    cmd.pass2Fields = ia.toArray();
0366:                }
0367:
0368:                // Fill in the fieldNo arrays now that everything is cool.
0369:                if (Debug.DEBUG) {
0370:                    System.out
0371:                            .println("MDB: Calling initMDFields() for each class");
0372:                }
0373:                for (int i = 0; i < classes.length; i++) {
0374:                    ClassMetaData cmd = classes[i];
0375:                    if (cmd.pcSuperMetaData == null)
0376:                        cmd.initMDFields();
0377:                }
0378:
0379:                for (int i = 0; i < classes.length; i++) {
0380:                    ClassMetaData cmd = classes[i];
0381:                    if (cmd.pcSuperMetaData == null)
0382:                        cmd.initMDFields2();
0383:                }
0384:
0385:                /**
0386:                 * Set flags in the meta data for the client to correctly handle
0387:                 * bidirectional relationships.
0388:                 */
0389:                setMasterDetailFlags(classes);
0390:
0391:                /**
0392:                 * Update the totalSubClassCount
0393:                 */
0394:                for (int i = 0; i < classes.length; i++) {
0395:                    ClassMetaData cmd = classes[i];
0396:                    cmd.totalNoOfSubClasses = getSubClassCount(cmd);
0397:                }
0398:
0399:                for (int i = 0; i < classes.length; i++) {
0400:                    ClassMetaData aClass = classes[i];
0401:                    if (aClass.objectIdClass != null) {
0402:                        try {
0403:                            validateIDClass(aClass);
0404:                        } catch (RuntimeException e) {
0405:                            aClass.addError(e, quiet);
0406:                        }
0407:                    }
0408:                }
0409:
0410:                // finish initialization of fetch groups
0411:                if (Debug.DEBUG) {
0412:                    System.out
0413:                            .println("MDB: Finishing fetch group initialization");
0414:                }
0415:                for (int i = 0; i < clen; i++)
0416:                    classes[i].finishFetchGroups();
0417:                for (int i = 0; i < clen; i++)
0418:                    classes[i].finishFetchGroups2();
0419:                for (int i = 0; i < clen; i++) {
0420:                    ClassMetaData cmd = classes[i];
0421:                    if (cmd.pcSuperMetaData == null)
0422:                        checkHeirachy(cmd);
0423:                }
0424:                for (int i = 0; i < clen; i++) {
0425:                    ClassMetaData cmd = classes[i];
0426:                    FieldMetaData[] fmds = cmd.fields;
0427:                    if (fmds == null)
0428:                        continue; // possible if previous error
0429:                    for (int j = 0; j < fmds.length; j++) {
0430:                        FieldMetaData.setStateMethodName(fmds[j]);
0431:                    }
0432:                }
0433:
0434:                // This must be done after all fmd's have been finished.
0435:                // This must set the inverseFieldNos
0436:                // and null the inverseFieldMetaData
0437:                for (int i = 0; i < classes.length; i++) {
0438:                    ClassMetaData cmd = classes[i];
0439:                    FieldMetaData[] fmds = cmd.stateFields;
0440:                    if (fmds == null)
0441:                        continue; // possible if previous error
0442:                    for (int j = 0; j < fmds.length; j++) {
0443:                        FieldMetaData fmd = fmds[j];
0444:                        if (fmd.inverseFieldMetaData != null) {
0445:                            fmd.inverseFieldNo = fmd.inverseFieldMetaData.managedFieldNo;
0446:                        }
0447:                    }
0448:                }
0449:
0450:                // Update the cacheStrat of the subclasses to that of the base class.
0451:                for (int i = 0; i < clen; i++) {
0452:                    ClassMetaData cmd = classes[i];
0453:                    if (cmd.pcSuperMetaData == null)
0454:                        cmd.overRideCacheStrategy();
0455:                }
0456:
0457:                // create QueryParam's for all the named queries
0458:                for (int i = 0; i < clen; i++) {
0459:                    ClassMetaData cmd = classes[i];
0460:                    try {
0461:                        createQueryParamsForNamedQueries(cmd);
0462:                    } catch (RuntimeException e) {
0463:                        cmd.addError(e, quiet);
0464:                    }
0465:                }
0466:
0467:                appIdUniqueMap = null;
0468:
0469:                // cleanup data structures not required after meta data generation
0470:                jmd.cleanupAfterMetaDataGeneration();
0471:
0472:                // check the meta data for consistency
0473:                jmd.validate();
0474:
0475:                return jmd;
0476:            }
0477:
0478:            protected void doHorizontal(ClassMetaData[] ca) {
0479:            }
0480:
0481:            protected void doEmbedded(ClassMetaData[] ca) {
0482:            }
0483:
0484:            protected void createHorizontalFieldMetaData(ClassMetaData cmd,
0485:                    boolean quiet) {
0486:                ClassMetaData super Cmd = cmd.horizontalCMD;
0487:                if (super Cmd == null)
0488:                    return;
0489:                if (super Cmd.fields == null)
0490:                    return;
0491:
0492:                Map fieldMap = new HashMap();
0493:                createFmdWithReflection(cmd.horizontalCMD, fieldMap, super Cmd
0494:                        .getShortName()
0495:                        + ".");
0496:                updateMDFromHorizontalSuper(cmd);
0497:                updateFmdFromMetadata(cmd.horizontalCMD, fieldMap, quiet,
0498:                        cmd.jdoClass.elements);
0499:                List fields = updateFmd(fieldMap, cmd, quiet);
0500:
0501:                for (int i = 0; i < fields.size(); i++) {
0502:                    FieldMetaData fieldMetaData = (FieldMetaData) fields.get(i);
0503:                    fieldMetaData.classMetaData = cmd;
0504:                    fieldMetaData.fake = true;
0505:                    fieldMetaData.origFmd = super Cmd.fields[i];
0506:                    fieldMetaData.horizontalFakeField = true;
0507:                }
0508:
0509:                cmd.horizontalFields = new FieldMetaData[fields.size()];
0510:                fields.toArray(cmd.horizontalFields);
0511:
0512:                fields.addAll(0, Arrays.asList(cmd.fields));
0513:                cmd.fields = new FieldMetaData[fields.size()];
0514:                fields.toArray(cmd.fields);
0515:
0516:                for (int i = cmd.fields.length - 1; i >= 0; i--) {
0517:                    cmd.fields[i].fieldNo = i;
0518:                }
0519:
0520:                updateScoFields(cmd);
0521:            }
0522:
0523:            /**
0524:             * Fill the superFieldCount and superFetchGroupCount values and
0525:             * build the stateFields arrays.
0526:             */
0527:            protected void calcSuperCounts(ClassMetaData[] classes) {
0528:                if (Debug.DEBUG) {
0529:                    System.out
0530:                            .println("MDB: Calcing superFieldCount and superFetchGroupCount "
0531:                                    + "filling stateFields");
0532:                }
0533:                int clen = classes.length;
0534:                for (int i = 0; i < clen; i++) {
0535:                    ClassMetaData cmd = classes[i];
0536:                    if (cmd.pcSuperMetaData == null) {
0537:                        cmd.calcSuperCounts();
0538:                    }
0539:                }
0540:            }
0541:
0542:            /**
0543:             * Set flags in the meta data for the client to correctly handle
0544:             * bidirectional relationships.
0545:             */
0546:            protected void setMasterDetailFlags(ClassMetaData[] classes) {
0547:                // nothing to do
0548:            }
0549:
0550:            /**
0551:             * This is invoked before fetch groups are built. Subclasses can override
0552:             * this to do additional processing.
0553:             */
0554:            protected void preBuildFetchGroupsHook() {
0555:            }
0556:
0557:            /**
0558:             * Second hook called late in the build process after all fields have
0559:             * been created and fetch groups have been built.
0560:             */
0561:            protected void postAllFieldsCreatedHook() {
0562:            }
0563:
0564:            private void createQueryParamsForNamedQueries(ClassMetaData cmd) {
0565:                JdoClass jdoClass = getClassInfo(cmd).jdoClass;
0566:                ArrayList queries = jdoClass.queries;
0567:                if (queries == null || queries.isEmpty())
0568:                    return;
0569:                int n = queries.size();
0570:                for (int i = 0; i < n; i++) {
0571:                    JdoQuery q = (JdoQuery) queries.get(i);
0572:                    if (cmd.getNamedQuery(q.name) != null) {
0573:                        throw BindingSupportImpl.getInstance().runtime(
0574:                                "There " + "is already a query called '"
0575:                                        + q.name + "' on " + cmd.qname + "\n"
0576:                                        + q.getContext());
0577:                    }
0578:                    cmd.addNamedQuery(q.name, new QueryDetails(cmd, q));
0579:                }
0580:            }
0581:
0582:            /**
0583:             * What is the default cache strategy?
0584:             */
0585:            public int getCdCacheStrategy() {
0586:                return MDStatics.CACHE_STRATEGY_YES;
0587:            }
0588:
0589:            /**
0590:             * Are references placed in the default fetch group?
0591:             */
0592:            public boolean isCdRefsInDefaultFetchGroup() {
0593:                return false;
0594:            }
0595:
0596:            /**
0597:             * Recursive method to calculate the total subclass count.
0598:             */
0599:            private int getSubClassCount(ClassMetaData cmd) {
0600:                if (cmd.pcSubclasses == null)
0601:                    return 0;
0602:                int count = cmd.pcSubclasses.length;
0603:                for (int i = 0; i < cmd.pcSubclasses.length; i++) {
0604:                    count += getSubClassCount(cmd.pcSubclasses[i]);
0605:                }
0606:                return count;
0607:            }
0608:
0609:            /**
0610:             * Resolve the ordering nodes for all collection fields with ordering.
0611:             */
0612:            protected void resolveOrdering(ClassMetaData cmd, boolean quiet) {
0613:                FieldMetaData[] fields = cmd.fields;
0614:                if (fields == null)
0615:                    return; // possible if previous errors
0616:                int flen = fields.length;
0617:                for (int i = 0; i < flen; i++) {
0618:                    FieldMetaData fmd = fields[i];
0619:                    if (fmd.ordering != null) {
0620:                        int len = fmd.ordering.length;
0621:                        try {
0622:                            for (int j = 0; j < len; j++) {
0623:                                fmd.ordering[j].resolve(queryParser,
0624:                                        fmd.elementTypeMetaData, false);
0625:                            }
0626:                        } catch (Exception e) {
0627:                            if (BindingSupportImpl.getInstance()
0628:                                    .isOwnFatalUserException(e)) {
0629:                                fmd.addError((RuntimeException) e, quiet);
0630:                            } else {
0631:                                RuntimeException jfue = BindingSupportImpl
0632:                                        .getInstance().runtime(
0633:                                                "Invalid ordering extension for field "
0634:                                                        + fmd.getQName(), e);
0635:                                fmd.addError(jfue, quiet);
0636:                            }
0637:                        }
0638:                    }
0639:                }
0640:            }
0641:
0642:            private void checkHeirachy(ClassMetaData cmd) {
0643:                if (cmd.pcSubclasses == null)
0644:                    return;
0645:                ClassMetaData[] pcSubs = cmd.pcSubclasses;
0646:                FetchGroup[] super FG = cmd.fetchGroups;
0647:                for (int i = 0; i < pcSubs.length; i++) {
0648:                    ClassMetaData pcSub = pcSubs[i];
0649:                    for (int j = 0; j < super FG.length; j++) {
0650:                        FetchGroup fetchGroup = super FG[j];
0651:                        FetchGroup subFG = pcSub.getFetchGroup(fetchGroup.name);
0652:                        if (subFG == null
0653:                                || subFG.super FetchGroup != fetchGroup) {
0654:                            throw BindingSupportImpl.getInstance().internal(
0655:                                    "FG hierachy broken");
0656:                        }
0657:                    }
0658:                    checkHeirachy(pcSub);
0659:                }
0660:            }
0661:
0662:            /**
0663:             * Throw a JDOFatalUserException for an unexpected extension.
0664:             */
0665:            public static void throwUnexpectedExtension(JdoExtension e) {
0666:                throw BindingSupportImpl.getInstance().runtime(
0667:                        "Extension not allowed here: " + e + "\n"
0668:                                + e.getContext());
0669:            }
0670:
0671:            /**
0672:             * Find all the primary key fields for cmd.
0673:             */
0674:            private void extractPrimaryKeyFields(ClassMetaData cmd,
0675:                    boolean quiet) {
0676:                // collect pk fields in  meta data order
0677:                ArrayList a = new ArrayList(4);
0678:                JdoElement[] ea = cmd.jdoClass.elements;
0679:                int n = ea.length;
0680:                for (int i = 0; i < n; i++) {
0681:                    JdoElement o = ea[i];
0682:                    if (!(o instanceof  JdoField))
0683:                        continue;
0684:                    FieldMetaData fmd = cmd
0685:                            .getFieldMetaData(((JdoField) o).name);
0686:                    if (fmd != null && fmd.primaryKey)
0687:                        a.add(fmd);
0688:                }
0689:
0690:                boolean appid = cmd.identityType == IDENTITY_TYPE_APPLICATION;
0691:                if (a.isEmpty()) {
0692:                    if (appid && cmd.pcSuperClass == null) {
0693:                        RuntimeException e = BindingSupportImpl
0694:                                .getInstance()
0695:                                .runtime(
0696:                                        "No primary key fields found for class with identity-type "
0697:                                                + "application and no persistence-capable-superclass\n"
0698:                                                + cmd.jdoClass.getContext());
0699:                        cmd.addError(e, quiet);
0700:                        return;
0701:                    }
0702:                } else {
0703:                    if (!appid && !cmd.horizontal) {
0704:                        RuntimeException e = BindingSupportImpl.getInstance()
0705:                                .runtime(
0706:                                        "Only classes with identity-type application may have "
0707:                                                + "primary-key fields\n"
0708:                                                + cmd.jdoClass.getContext());
0709:                        cmd.addError(e, quiet);
0710:                    }
0711:                    cmd.pkFields = new FieldMetaData[a.size()];
0712:                    a.toArray(cmd.pkFields);
0713:
0714:                    initPkFieldDefaultValue(cmd, a, quiet);
0715:                }
0716:            }
0717:
0718:            private void initPkFieldDefaultValue(ClassMetaData cmd,
0719:                    ArrayList a, boolean quiet) {
0720:                if (cmd.identityType != IDENTITY_TYPE_APPLICATION)
0721:                    return;
0722:                try {
0723:                    Object inst = null;
0724:                    if (cmd.objectIdClass != null) {
0725:                        inst = cmd.objectIdClass.newInstance();
0726:                    } else {
0727:                        inst = cmd.cls.newInstance();
0728:
0729:                    }
0730:                    for (int i = 0; i < a.size(); i++) {
0731:                        FieldMetaData fmd = (FieldMetaData) a.get(i);
0732:                        Field field = null;
0733:                        Class cls = inst.getClass();
0734:                        for (; cls != null;) {
0735:                            try {
0736:                                field = cls.getDeclaredField(fmd.name);
0737:                                break;
0738:                            } catch (NoSuchFieldException e) {
0739:                                cls = cls.getSuperclass();
0740:                            } catch (SecurityException e) {
0741:                                e.printStackTrace(System.out);
0742:                                break;
0743:                            }
0744:                        }
0745:                        if (field != null) {
0746:                            ClassHelper.get().setAccessible(field, true);
0747:                            fmd.setPkDefaultValue(field.get(inst));
0748:                        }
0749:                    }
0750:                } catch (Exception e) {
0751:                    if (!BindingSupportImpl.getInstance().isOwnException(e)) {
0752:                        e = BindingSupportImpl.getInstance().runtime(
0753:                                e.getMessage(), e);
0754:                    }
0755:                    cmd.addError((RuntimeException) e, quiet);
0756:                    if (!quiet) {
0757:                        throw (RuntimeException) e;
0758:                    }
0759:                }
0760:            }
0761:
0762:            /**
0763:             * Create a single JdoRoot from all packages.
0764:             */
0765:            private JdoRoot buildSingleJdoRoot(JdoRoot[] roots) {
0766:
0767:                // process all the JdoRoot's that are not query only resources
0768:                HashMap classMap = new HashMap();
0769:                ArrayList packageList = new ArrayList();
0770:                int n = roots.length;
0771:                for (int i = 0; i < n; i++) {
0772:                    JdoRoot root = roots[i];
0773:                    if (root.isQueryMetaData())
0774:                        continue;
0775:                    for (int k = root.packages.length - 1; k >= 0; k--) {
0776:                        JdoPackage p = root.packages[k];
0777:                        boolean addPackage = true;
0778:                        for (int j = p.classes.length - 1; j >= 0; j--) {
0779:                            JdoClass cls = p.classes[j];
0780:                            String qname = cls.getQName();
0781:                            String other = (String) jmd.classResourceMap
0782:                                    .get(qname);
0783:                            if (other != null) {
0784:
0785:                                if (other.equals(root.name)) {
0786:                                    throw BindingSupportImpl
0787:                                            .getInstance()
0788:                                            .runtime(
0789:                                                    "Class "
0790:                                                            + p.classes[j].name
0791:                                                            + " is defined more than once in "
0792:                                                            + root.name);
0793:                                } else {
0794:                                    throw BindingSupportImpl.getInstance()
0795:                                            .runtime(
0796:                                                    "Class "
0797:                                                            + p.classes[j].name
0798:                                                            + " is defined in "
0799:                                                            + other + " and "
0800:                                                            + root.name);
0801:                                }
0802:
0803:                            }
0804:                            jmd.classResourceMap.put(qname, root.name);
0805:                            classMap.put(qname, cls);
0806:                        }
0807:                        if (addPackage == true)
0808:                            packageList.add(p);
0809:                    }
0810:                }
0811:
0812:                // move all JdoQuery's to the meta data for the classes they are for
0813:                for (int i = 0; i < n; i++) {
0814:                    JdoRoot root = roots[i];
0815:                    if (!root.isQueryMetaData())
0816:                        continue;
0817:                    for (int k = root.packages.length - 1; k >= 0; k--) {
0818:                        JdoPackage p = root.packages[k];
0819:                        for (int j = p.classes.length - 1; j >= 0; j--) {
0820:                            JdoClass cls = p.classes[j];
0821:                            if (cls.queries == null)
0822:                                continue;
0823:                            for (Iterator t = cls.queries.iterator(); t
0824:                                    .hasNext();) {
0825:                                JdoQuery q = (JdoQuery) t.next();
0826:                                String qname = q.getCandidateClass();
0827:                                JdoClass target = (JdoClass) classMap
0828:                                        .get(qname);
0829:                                if (target == null) {
0830:                                    throw BindingSupportImpl
0831:                                            .getInstance()
0832:                                            .runtime(
0833:                                                    "Candidate class for query is not "
0834:                                                            + "defined in the meta data: "
0835:                                                            + qname + "\n"
0836:                                                            + q.getContext());
0837:                                }
0838:                                target.addJdoQuery(q);
0839:                            }
0840:                        }
0841:                    }
0842:                }
0843:
0844:                // make a new single JdoRoot
0845:                JdoRoot root = new JdoRoot();
0846:                root.packages = new JdoPackage[packageList.size()];
0847:                root.name = "combined";
0848:                packageList.toArray(root.packages);
0849:                // Note that we have not changed the parent field on each package.
0850:                // This still points at the original JdoRoot so that error messages
0851:                // can display the correct filename.
0852:
0853:                return root;
0854:            }
0855:
0856:            /**
0857:             * Load class name using our loader.
0858:             */
0859:            private Class loadClass(String name) throws ClassNotFoundException {
0860:                return ClassHelper.get().classForName(name, false, loader);
0861:            }
0862:
0863:            /**
0864:             * Create tempory meta data for a package. This is used for defaults
0865:             * for classes etc.
0866:             */
0867:            private PackageMetaData createPackageMetaData(JdoPackage p) {
0868:                PackageMetaData pmd = new PackageMetaData();
0869:                pmd.nameWithDot = p.name + ".";
0870:                pmd.jdoPackage = p;
0871:                return pmd;
0872:            }
0873:
0874:            /**
0875:             * Create meta data for an interface in package pmd.
0876:             */
0877:            private InterfaceMetaData createInterfaceMetaData(
0878:                    PackageMetaData pmd, JdoExtension ext) {
0879:                String qname = ext.getString();
0880:                if (qname.indexOf('.') < 0)
0881:                    qname = pmd.nameWithDot + qname;
0882:                Class cls;
0883:                try {
0884:                    cls = loadClass(qname);
0885:                } catch (ClassNotFoundException e) {
0886:                    throw BindingSupportImpl.getInstance().runtime(
0887:                            "Interface not found: " + qname + "\n"
0888:                                    + ext.getContext(), e);
0889:                }
0890:                if (!cls.isInterface()) {
0891:                    throw BindingSupportImpl.getInstance().runtime(
0892:                            "Expected interface, found class: " + qname + "\n"
0893:                                    + ext.getContext());
0894:                }
0895:                return new InterfaceMetaData(cls);
0896:            }
0897:
0898:            /**
0899:             * Create basic meta data for class cls in package pmd. This does not
0900:             * pickup the fields. It loads all classes etc and finds some class
0901:             * extensions.
0902:             */
0903:            private ClassMetaData createMetaData(PackageMetaData pmd,
0904:                    JdoClass jdoCls, boolean quiet) {
0905:                ClassMetaData cmd = new ClassMetaData(jdoCls, jmd);
0906:                ClassInfo classInfo = getClassInfo(cmd);
0907:                classInfo.jdoClass = jdoCls;
0908:
0909:                // init defaults before we do anything else
0910:                cmd.packageNameWithDot = pmd.nameWithDot;
0911:                classInfo.refsInDefaultFetchGroup = isCdRefsInDefaultFetchGroup();
0912:                cmd.cacheStrategy = getCdCacheStrategy();
0913:                cmd.setObjectIdClasssRequired(jdoCls.objectIdClasssRequired);
0914:
0915:                // load the PC class
0916:                try {
0917:                    cmd.cls = loadClass(cmd.qname);
0918:                } catch (ClassNotFoundException e) {
0919:                    RuntimeException x = BindingSupportImpl.getInstance()
0920:                            .runtime(
0921:                                    "Class not found: " + cmd.qname + "\n"
0922:                                            + jdoCls.getContext(), e);
0923:                    cmd.addError(x, quiet);
0924:                    return cmd;
0925:                }
0926:                if (cmd.cls.isInterface()) {
0927:                    RuntimeException x = BindingSupportImpl.getInstance()
0928:                            .runtime(
0929:                                    "Expected class, found interface: "
0930:                                            + cmd.qname + "\n"
0931:                                            + jdoCls.getContext());
0932:                    cmd.addError(x, quiet);
0933:                    return cmd;
0934:                }
0935:
0936:                // load its persistence-capable-superclass (if any)
0937:                String qname = jdoCls.getPCSuperClassQName();
0938:                if (qname != null) {
0939:                    try {
0940:                        cmd.pcSuperClass = loadClass(qname);
0941:                    } catch (ClassNotFoundException e) {
0942:                        RuntimeException x = BindingSupportImpl.getInstance()
0943:                                .runtime(
0944:                                        "persistence-capable-superclass not found: "
0945:                                                + qname + "\n"
0946:                                                + jdoCls.getContext(), e);
0947:                        cmd.addError(x, quiet);
0948:                        return cmd;
0949:                    }
0950:                }
0951:
0952:                checkForHorizontal(jdoCls, cmd);
0953:                updateIdMetaData(cmd, jdoCls);
0954:
0955:                // pickup some class extensions
0956:                JdoElement[] elements = jdoCls.elements;
0957:                int n = elements.length;
0958:                for (int i = 0; i < n; i++) {
0959:                    JdoElement o = elements[i];
0960:                    if (o instanceof  JdoExtension) {
0961:                        JdoExtension e = (JdoExtension) o;
0962:                        switch (e.key) {
0963:                        case JdoExtensionKeys.READ_ONLY:
0964:                            try {
0965:                                cmd.readOnly = e.getBoolean();
0966:                            } catch (RuntimeException x) {
0967:                                cmd.addError(x, quiet);
0968:                            }
0969:                            break;
0970:                        case JdoExtensionKeys.CACHE_STRATEGY:
0971:                            try {
0972:                                cmd.cacheStrategy = e.getEnum(MDE.CACHE_ENUM);
0973:                            } catch (RuntimeException x) {
0974:                                cmd.addError(x, quiet);
0975:                            }
0976:                            break;
0977:                        case JdoExtensionKeys.DELETE_ORPHANS:
0978:                            try {
0979:                                cmd.deleteOrphans = e.getBoolean();
0980:                            } catch (RuntimeException x) {
0981:                                cmd.addError(x, quiet);
0982:                            }
0983:                            break;
0984:                        case JdoExtensionKeys.OIDS_IN_DEFAULT_FETCH_GROUP:
0985:                            try {
0986:                                getClassInfo(cmd).refsInDefaultFetchGroup = e
0987:                                        .getBoolean();
0988:                            } catch (RuntimeException x) {
0989:                                cmd.addError(x, quiet);
0990:                            }
0991:                            break;
0992:                        case JdoExtensionKeys.CREATE_OID_AT_MAKE_PERSISTENT:
0993:                            // ignore - no longer required
0994:                            break;
0995:                        }
0996:                    }
0997:                }
0998:
0999:                return cmd;
1000:            }
1001:
1002:            private void updateIdMetaData(ClassMetaData cmd, JdoClass jdoCls) {
1003:                // load its objectid-class (if any)
1004:                cmd.identityType = jdoCls.identityType;
1005:                if (cmd.identityType == IDENTITY_TYPE_APPLICATION) {
1006:                    String qname = jdoCls.getObjectIdClassQName();
1007:                    if (qname == null) {
1008:                        if (cmd.isObjectIdClasssRequired()) {
1009:                            RuntimeException x = BindingSupportImpl
1010:                                    .getInstance().runtime(
1011:                                            "objectid-class is required for application identity\n"
1012:                                                    + jdoCls.getContext());
1013:                            cmd.addError(x, quiet);
1014:                        }
1015:                        return;
1016:                    }
1017:
1018:                    String pcRootClsName = (String) appIdUniqueMap.get(qname);
1019:                    if (pcRootClsName == null) {
1020:                        appIdUniqueMap.put(qname, jdoCls.getQName());
1021:                    } else {
1022:                        RuntimeException x = BindingSupportImpl.getInstance()
1023:                                .invalidOperation(
1024:                                        "The objectid-class for "
1025:                                                + jdoCls.getQName()
1026:                                                + " has already been used for "
1027:                                                + pcRootClsName + ": " + qname
1028:                                                + "\n" + jdoCls.getContext());
1029:                        cmd.addError(x, quiet);
1030:                        return;
1031:                    }
1032:
1033:                    try {
1034:                        cmd.objectIdClass = loadClass(qname);
1035:                    } catch (ClassNotFoundException e) {
1036:                        RuntimeException x = BindingSupportImpl
1037:                                .getInstance()
1038:                                .runtime(
1039:                                        "objectid-class not found: " + qname
1040:                                                + "\n" + jdoCls.getContext(), e);
1041:                        cmd.addError(x, quiet);
1042:                        return;
1043:                    }
1044:                } else if (cmd.identityType == IDENTITY_TYPE_NONDURABLE) {
1045:                    RuntimeException x = BindingSupportImpl.getInstance()
1046:                            .runtime(
1047:                                    "nondurable identity-type is not supported\n"
1048:                                            + jdoCls.getContext());
1049:                    cmd.addError(x, quiet);
1050:                    return;
1051:                } else {
1052:                    cmd.identityType = IDENTITY_TYPE_DATASTORE;
1053:                    if (jdoCls.objectIdClass != null) {
1054:                        RuntimeException x = BindingSupportImpl.getInstance()
1055:                                .runtime(
1056:                                        "objectid-class is only allowed for application identity\n"
1057:                                                + jdoCls.getContext());
1058:                        cmd.addError(x, quiet);
1059:                        return;
1060:                    }
1061:                }
1062:                //        } else {
1063:                //            if (jdoCls.objectIdClass != null) {
1064:                //                RuntimeException x = BindingSupportImpl.getInstance().runtime("objectid-class is not allowed as class " +
1065:                //                        "has a persistence-capable-superclass\n" +
1066:                //                        jdoCls.getContext());
1067:                //                cmd.addError(x, quiet);
1068:                //                return cmd;
1069:                //            }
1070:                //        }
1071:            }
1072:
1073:            /**
1074:             * Calculate if this class is horizontally mapped.
1075:             * @param jdoCls
1076:             * @param cmd
1077:             */
1078:            protected void checkForHorizontal(JdoClass jdoCls, ClassMetaData cmd) {
1079:            }
1080:
1081:            /**
1082:             * Validate the application id class. This also fills
1083:             * {@link FieldMetaData#objectidClassField}.
1084:             */
1085:            private void validateIDClass(ClassMetaData cmd) {
1086:                Class idClass = cmd.objectIdClass;
1087:
1088:                if (!Modifier.isPublic(idClass.getModifiers())) {
1089:                    throw BindingSupportImpl.getInstance().runtime(
1090:                            "Application id class '" + idClass.getName()
1091:                                    + "' must be public");
1092:                }
1093:
1094:                if (idClass.isInterface()) {
1095:                    throw BindingSupportImpl.getInstance().runtime(
1096:                            "Application id class '" + idClass.getName()
1097:                                    + "' may not be an interface");
1098:                }
1099:
1100:                FieldMetaData[] pkFields = cmd.pkFields;
1101:                for (int i = 0; i < pkFields.length; i++) {
1102:                    pkFields[i].getObjectidClassField();
1103:                }
1104:
1105:                // Must implement java.io.Serializable
1106:                if (!Serializable.class.isAssignableFrom(idClass)) {
1107:                    throw BindingSupportImpl
1108:                            .getInstance()
1109:                            .runtime(
1110:                                    "Application id class '"
1111:                                            + idClass.getName()
1112:                                            + "' does not implement java.io.Serializable");
1113:                }
1114:
1115:                // Must have default constructor
1116:                Constructor[] constructors = idClass.getDeclaredConstructors();
1117:                boolean foundDefaultCon = false;
1118:                for (int i = 0; i < constructors.length; i++) {
1119:                    Constructor constructor = constructors[i];
1120:                    if (!Modifier.isPublic(constructor.getModifiers()))
1121:                        continue;
1122:                    if (constructor.getParameterTypes().length != 0)
1123:                        continue;
1124:                    foundDefaultCon = true;
1125:                }
1126:                if (!foundDefaultCon) {
1127:                    throw BindingSupportImpl
1128:                            .getInstance()
1129:                            .runtime(
1130:                                    "Application id class '"
1131:                                            + idClass.getName()
1132:                                            + "' does not have a public no-arg constructor");
1133:                }
1134:
1135:                // Must have String constructor
1136:                boolean foundStringCon = false;
1137:                for (int i = 0; i < constructors.length; i++) {
1138:                    Constructor constructor = constructors[i];
1139:                    if (!Modifier.isPublic(constructor.getModifiers()))
1140:                        continue;
1141:                    if (constructor.getParameterTypes().length != 1)
1142:                        continue;
1143:                    if (constructor.getParameterTypes()[0]
1144:                            .isAssignableFrom(String.class)) {
1145:                        foundStringCon = true;
1146:                    }
1147:                }
1148:                if (!foundStringCon) {
1149:                    throw BindingSupportImpl
1150:                            .getInstance()
1151:                            .runtime(
1152:                                    "Application id class '"
1153:                                            + idClass.getName()
1154:                                            + "' does not have a public constructor that accepts a String parameter");
1155:                }
1156:
1157:                // Must override toString
1158:                try {
1159:                    Method tos = null;
1160:                    for (Class c = idClass; c != Object.class; c = c
1161:                            .getSuperclass()) {
1162:                        try {
1163:                            tos = c.getDeclaredMethod("toString", null);
1164:                            break;
1165:                        } catch (NoSuchMethodException e) {
1166:                            // ignore
1167:                        }
1168:                    }
1169:                    if (tos == null) {
1170:                        throw BindingSupportImpl.getInstance().runtime(
1171:                                "Application id class '" + idClass.getName()
1172:                                        + "' must override toString");
1173:                    }
1174:                } catch (SecurityException e) {
1175:                    throw BindingSupportImpl.getInstance().exception(
1176:                            e.getMessage(), e);
1177:                }
1178:            }
1179:
1180:            /**
1181:             * Create the FieldMetaData for class cmd. This finds all fields using
1182:             * reflection and merges this with the JdoField information from the
1183:             * .jdo files.
1184:             */
1185:            private void createFieldMetaData(ClassMetaData cmd, boolean quiet) {
1186:                if (cmd.pcSuperMetaData != null)
1187:                    return;
1188:                createFieldMetaDataImp(cmd, quiet);
1189:            }
1190:
1191:            protected void createEmbeddeFieldMetaData(ClassMetaData cmd,
1192:                    boolean quiet) {
1193:                if (cmd.pcSuperMetaData != null)
1194:                    return;
1195:                createEmbeddeFieldMetaDataImp(cmd, quiet);
1196:            }
1197:
1198:            /**
1199:             * Update all the jdo metadata for horizontal fields from horizontal superclass.
1200:             */
1201:            private void updateMDFromHorizontalSuper(ClassMetaData cmd) {
1202:                if (cmd.horizontalCMD == null)
1203:                    return;
1204:
1205:                JdoElement[] ea = cmd.jdoClass.elements;
1206:                List newFields = new ArrayList(Arrays.asList(ea));
1207:                JdoElement[] hor = cmd.horizontalCMD.jdoClass.elements;
1208:                final String prefix = cmd.horizontalCMD.getShortName() + ".";
1209:
1210:                for (int i = 0; i < hor.length; i++) {
1211:                    JdoElement o = hor[i];
1212:                    if (!(o instanceof  JdoField))
1213:                        continue;
1214:                    JdoField jdoField = (JdoField) o;
1215:
1216:                    /**
1217:                     * If this field is descibed in subclass then merge it, else just copy
1218:                     * it to the subclass
1219:                     */
1220:                    JdoField extendedField = findJdoFieldIn(ea, prefix
1221:                            + jdoField.name);
1222:                    if (extendedField == null) {
1223:                        extendedField = jdoField.createCopy(cmd.jdoClass);
1224:                        extendedField.name = prefix + extendedField.name;
1225:                        newFields.add(extendedField);
1226:                    } else {
1227:                        extendedField.synchWith(jdoField,
1228:                                Collections.EMPTY_SET, false);
1229:                    }
1230:                }
1231:                ea = new JdoElement[newFields.size()];
1232:                newFields.toArray(ea);
1233:                cmd.jdoClass.elements = ea;
1234:            }
1235:
1236:            private JdoField findJdoFieldIn(JdoElement[] elements, String name) {
1237:                for (int i = 0; i < elements.length; i++) {
1238:                    JdoElement element = elements[i];
1239:                    if (!(element instanceof  JdoField))
1240:                        continue;
1241:                    JdoField jdoField = (JdoField) element;
1242:                    if (jdoField.name.equals(name)) {
1243:                        return jdoField;
1244:                    }
1245:                }
1246:                return null;
1247:            }
1248:
1249:            private void createEmbeddeFieldMetaDataImp(ClassMetaData cmd,
1250:                    boolean quiet) {
1251:                ArrayList currentFields = new ArrayList(Arrays
1252:                        .asList(cmd.fields));
1253:                HashMap parents = new HashMap(cmd.fields.length * 5);
1254:                FieldMetaData fmd = null;
1255:                for (int i = 0; i < currentFields.size(); i++) {
1256:                    fmd = (FieldMetaData) currentFields.get(i);
1257:
1258:                    if (fmd.isEmbeddedRef()) {
1259:                        ClassMetaData embeddedCmd = fmd.typeMetaData;
1260:
1261:                        Map fieldMap = new HashMap();
1262:                        createFmdWithReflection(embeddedCmd, fieldMap, fmd.name
1263:                                + "/");
1264:
1265:                        /**
1266:                         * Make a copy of the jdoFields as found on the original class
1267:                         * Extract info from the extensions found on the embedded ref field
1268:                         * and apply it to the relevant jdoFields.
1269:                         */
1270:                        Map copiedJdoFields = new HashMap();
1271:                        for (int j = 0; j < embeddedCmd.jdoClass.elements.length; j++) {
1272:                            JdoElement element = embeddedCmd.jdoClass.elements[j];
1273:                            if (!(element instanceof  JdoField))
1274:                                continue;
1275:                            JdoField copy = ((JdoField) element)
1276:                                    .createCopy(cmd.jdoClass);
1277:                            //map it to old name
1278:                            copiedJdoFields.put(copy.name, copy);
1279:                            copy.origName = copy.name;
1280:                            copy.name = fmd.name + "/" + copy.name;
1281:                            if (fmd.jdoField != null
1282:                                    && fmd.jdoField.extensions != null) {
1283:                                JdoExtension ext = JdoExtension.find(
1284:                                        JdoExtensionKeys.FIELD, copy.origName,
1285:                                        fmd.jdoField.extensions);
1286:                                if (ext != null)
1287:                                    copy.applyEmbeddedExtensions(ext.nested);
1288:                            } else {
1289:                                copy.applyEmbeddedExtensions(null);
1290:                            }
1291:                        }
1292:
1293:                        //create new JdoField's from extensions
1294:                        if (fmd.jdoField != null
1295:                                && fmd.jdoField.extensions != null) {
1296:                            JdoExtension exts[] = fmd.jdoField.extensions;
1297:                            Iterator iter = fieldMap.keySet().iterator();
1298:                            while (iter.hasNext()) {
1299:                                String name = (String) iter.next();
1300:                                name = name
1301:                                        .substring((fmd.name + "/").length());
1302:                                if (copiedJdoFields.containsKey(name))
1303:                                    continue;
1304:                                JdoExtension ext = JdoExtension.find(
1305:                                        JdoExtensionKeys.FIELD, name, exts);
1306:                                if (ext != null) {
1307:                                    JdoField newJdoField = new JdoField(
1308:                                            fmd.jdoField);
1309:                                    newJdoField.name = fmd.name + "/" + name;
1310:                                    newJdoField
1311:                                            .applyEmbeddedExtensions(ext.nested);
1312:                                    copiedJdoFields.put(name, newJdoField);
1313:                                }
1314:                            }
1315:                        }
1316:
1317:                        JdoElement[] els = new JdoElement[copiedJdoFields
1318:                                .size()];
1319:                        copiedJdoFields.values().toArray(els);
1320:
1321:                        updateFmdFromMetadata(embeddedCmd, fieldMap, quiet, els);
1322:                        List fields = updateFmd(fieldMap, cmd, quiet);
1323:                        findNullIndicationFmd(fields, fmd);
1324:
1325:                        for (int j = 0; j < fields.size(); j++) {
1326:                            FieldMetaData fieldMetaData = (FieldMetaData) fields
1327:                                    .get(j);
1328:                            fieldMetaData.classMetaData = cmd;
1329:                            fieldMetaData.fake = true;
1330:                            fieldMetaData.origFmd = embeddedCmd.fields[j];
1331:                            fieldMetaData.embeddedFakeField = true;
1332:
1333:                            //look for recursive embedded field
1334:                            checkRecursiveEmbedded(fieldMetaData, fmd, parents);
1335:                        }
1336:
1337:                        fmd.embeddedFmds = new FieldMetaData[fields.size()];
1338:                        fields.toArray(fmd.embeddedFmds);
1339:
1340:                        /**
1341:                         * Look for nullIndicator
1342:                         * The nullIndicator might be a column or a field of the embedded class.
1343:                         * If it is a column then we must check if there is a field with the same
1344:                         * column name. If there is then it must be used as the null indicator.
1345:                         * Else we must create a fake field with the supplied column name to act as
1346:                         * the nullIndicator.
1347:                         */
1348:                        if (fmd.jdoField.extensions != null) {
1349:                            for (int j = 0; j < fmd.jdoField.extensions.length; j++) {
1350:                                JdoExtension ext = fmd.jdoField.extensions[j];
1351:                                if (ext.key == JdoExtensionKeys.NULL_INDICATOR) {
1352:                                    //must add fake field
1353:                                }
1354:                            }
1355:                        }
1356:                        currentFields.addAll(fields);
1357:                    }
1358:                }
1359:
1360:                cmd.fields = new FieldMetaData[currentFields.size()];
1361:                currentFields.toArray(cmd.fields);
1362:
1363:                for (int j = cmd.fields.length - 1; j >= 0; j--) {
1364:                    cmd.fields[j].fieldNo = j;
1365:                }
1366:
1367:                updateScoFields(cmd);
1368:
1369:                if (cmd.pcSubclasses != null) {
1370:                    for (int i = 0; i < cmd.pcSubclasses.length; i++) {
1371:                        createEmbeddeFieldMetaDataImp(cmd.pcSubclasses[i],
1372:                                quiet);
1373:                    }
1374:                }
1375:            }
1376:
1377:            private void findNullIndicationFmd(List fields, FieldMetaData fmd) {
1378:                for (int j = 0; j < fields.size(); j++) {
1379:                    FieldMetaData fieldMetaData = (FieldMetaData) fields.get(j);
1380:                    if (fieldMetaData.jdoField != null
1381:                            && fieldMetaData.jdoField.nullIndicator) {
1382:                        fmd.setNullIndicatorFmd(fieldMetaData);
1383:                        break;
1384:                    }
1385:                }
1386:            }
1387:
1388:            private void checkRecursiveEmbedded(FieldMetaData fieldMetaData,
1389:                    FieldMetaData fmd, HashMap parents) {
1390:                if (fieldMetaData.jdoField != null
1391:                        && fieldMetaData.isDirectRef()) {
1392:                    JdoExtension ext = null;
1393:                    if (fieldMetaData.jdoField.extensions != null) {
1394:                        ext = JdoExtension.find(JdoExtensionKeys.EMBEDDED,
1395:                                fieldMetaData.jdoField.extensions);
1396:                    }
1397:                    if (ext != null) {
1398:                        if (ext.getBoolean()) {
1399:                            fieldMetaData.embedded = true;
1400:                        } else {
1401:                            fieldMetaData.embedded = false;
1402:                        }
1403:                    } else {
1404:                        if (fieldMetaData.embedded) {
1405:                            HashSet parentTypes = new HashSet(5);
1406:                            FieldMetaData field = fmd;
1407:                            while (field != null) {
1408:                                ClassMetaData refClass = field.typeMetaData;
1409:                                while (refClass != null) {
1410:                                    parentTypes.add(refClass);
1411:                                    refClass = refClass.pcSuperMetaData;
1412:                                }
1413:                                FieldMetaData tempParent = (FieldMetaData) parents
1414:                                        .get(field);
1415:                                if (tempParent == null) {
1416:                                    refClass = field.classMetaData;
1417:                                    while (refClass != null) {
1418:                                        parentTypes.add(refClass);
1419:                                        refClass = refClass.pcSuperMetaData;
1420:                                    }
1421:                                }
1422:                                if (parentTypes
1423:                                        .contains(fieldMetaData.typeMetaData)) {
1424:                                    fieldMetaData.embedded = false;
1425:                                    break;
1426:                                }
1427:                                field = tempParent;
1428:                            }
1429:                        }
1430:                    }
1431:                }
1432:            }
1433:
1434:            /**
1435:             * Create the FieldMetaData for class cmd and recursively all of its
1436:             * subclasses.
1437:             */
1438:            private void createFieldMetaDataImp(ClassMetaData cmd, boolean quiet) {
1439:                HashMap fieldMap = new HashMap(); // name -> FieldMetaData
1440:                createFmdWithReflection(cmd, fieldMap, "");
1441:                updateFmdFromMetadata(cmd, fieldMap, quiet,
1442:                        cmd.jdoClass.elements);
1443:                List fields = updateFmd(fieldMap, cmd, quiet);
1444:                finalizeFmds(fields, cmd, quiet);
1445:            }
1446:
1447:            /**
1448:             * extract all the persistent and transactional fields and fill in more info.
1449:             * Return a list of managed fields.
1450:             */
1451:            private List updateFmd(Map fieldMap, ClassMetaData cmd,
1452:                    boolean quiet) {
1453:                ArrayList fields = new ArrayList();
1454:                FieldMetaData fmd = null;
1455:                for (Iterator i = fieldMap.values().iterator(); i.hasNext();) {
1456:                    fmd = (FieldMetaData) i.next();
1457:                    if (fmd.persistenceModifier == PERSISTENCE_MODIFIER_NONE)
1458:                        continue;
1459:                    JdoField jdoField = fmd.jdoField;
1460:                    if (Modifier.isTransient(fmd.modifiers)) {
1461:                        if (jdoField == null)
1462:                            continue;
1463:                    }
1464:                    fields.add(fmd);
1465:                    Class tt = fmd.componentType;
1466:                    if (tt == null)
1467:                        tt = fmd.type;
1468:                    fmd.typeMetaData = (ClassMetaData) classMap.get(tt);
1469:                    if (fmd.category == 0) {
1470:                        fmd.category = mdutils.getFieldCategory(
1471:                                fmd.persistenceModifier, fmd.type,
1472:                                classAndInterfaceMap);
1473:                    }
1474:                    if (fmd.category == MDStatics.CATEGORY_COLLECTION
1475:                            || fmd.category == MDStatics.CATEGORY_ARRAY
1476:                            || fmd.category == MDStatics.CATEGORY_MAP) {
1477:                        fmd.collectionDiffType = true;
1478:                    }
1479:                    if ((!fmd.embedded && fmd.category == CATEGORY_REF || fmd.category == CATEGORY_POLYREF)
1480:                            && (jdoField == null || jdoField.defaultFetchGroup == NOT_SET)) {
1481:                        fmd.defaultFetchGroup = getClassInfo(cmd).refsInDefaultFetchGroup;
1482:                    }
1483:                    if (fmd.category == MDStatics.CATEGORY_TRANSACTIONAL
1484:                            && fmd.scoField == true) {
1485:                        fmd.scoField = false;
1486:                    }
1487:                    if (fmd.category == MDStatics.CATEGORY_EXTERNALIZED) {
1488:                        if (fmd.externalizer == null) {
1489:                            fmd.externalizer = getExternalizerForType(fmd.type);
1490:                        }
1491:                        fmd.scoField = false;
1492:                    }
1493:                    if (fmd.category != MDStatics.CATEGORY_TRANSACTIONAL) {
1494:                        try {
1495:                            fillCollectionMetaData(fmd);
1496:                        } catch (RuntimeException e) {
1497:                            fmd.addError(e, quiet);
1498:                        }
1499:                    }
1500:                }
1501:                // sort by field name i.e. into fieldNo order
1502:                Collections.sort(fields);
1503:                return fields;
1504:            }
1505:
1506:            /**
1507:             * Look at all the meta data from .jdo files and merge it in.
1508:             */
1509:            private void updateFmdFromMetadata(ClassMetaData cmd, Map fieldMap,
1510:                    boolean quiet, JdoElement[] ea) {
1511:                int n = ea.length;
1512:                for (int i = 0; i < n; i++) {
1513:                    JdoElement o = ea[i];
1514:                    if (!(o instanceof  JdoField))
1515:                        continue;
1516:                    JdoField jdoField = (JdoField) o;
1517:                    if (jdoField.persistenceModifier == PERSISTENCE_MODIFIER_NONE) {
1518:                        fieldMap.remove(jdoField.name);
1519:                        continue;
1520:                    }
1521:
1522:                    FieldMetaData fmd = (FieldMetaData) fieldMap
1523:                            .get(jdoField.name);
1524:                    /**
1525:                     * The fmd might be null because w
1526:                     */
1527:                    if (fmd == null) {
1528:                        final String prefix = cmd.getShortName() + ".";
1529:                        if (jdoField.name.startsWith(prefix)) {
1530:                            String name = jdoField.name.substring(prefix
1531:                                    .length());
1532:                            fmd = (FieldMetaData) fieldMap.get(name);
1533:                        }
1534:                    }
1535:                    if (fmd == null) {
1536:                        int cIndex = jdoField.name.lastIndexOf("/");
1537:                        if (cIndex != -1) {
1538:                            String name = jdoField.name.substring(cIndex);
1539:                            fmd = (FieldMetaData) fieldMap.get(name);
1540:                        }
1541:                    }
1542:                    try {
1543:                        if (fmd == null) {
1544:                            if (cmd.horizontal
1545:                                    || (cmd.horizontalCMD != null && jdoField.name
1546:                                            .startsWith(cmd.horizontalCMD
1547:                                                    .getShortName()
1548:                                                    + "."))) {
1549:                                //this is a metadata for a horizontal field so ignore it for now
1550:                                continue;
1551:                            }
1552:                            throw BindingSupportImpl.getInstance().runtime(
1553:                                    "Field " + jdoField.name + " not found on "
1554:                                            + cmd.qname + "\n"
1555:                                            + jdoField.getContext());
1556:                        }
1557:                        if (fmd.jdoField != null) {
1558:                            throw BindingSupportImpl.getInstance().runtime(
1559:                                    "Duplicate meta data for field "
1560:                                            + jdoField.name + "\n"
1561:                                            + jdoField.getContext());
1562:                        }
1563:                        fmd.jdoField = jdoField;
1564:                        fmd.cascadeType = jdoField.cascadeType;
1565:
1566:                        if (jdoField.persistenceModifier != NOT_SET) {
1567:                            fmd.persistenceModifier = jdoField.persistenceModifier;
1568:                        }
1569:
1570:                        // do not allow static or final fields
1571:                        if (!mdutils.isPersistentModifiers(fmd.modifiers)) {
1572:                            throw BindingSupportImpl.getInstance().runtime(
1573:                                    "Field " + jdoField.name
1574:                                            + " is static and/or final\n"
1575:                                            + jdoField.getContext());
1576:                        }
1577:
1578:                        // fill in more basic info
1579:                        fmd.primaryKey = jdoField.primaryKey;
1580:                        fmd.nullValue = jdoField.nullValue;
1581:                        if (fetchGroupBuilder
1582:                                .findFetchGroupExt(jdoField.extensions) != null) {
1583:                            fmd.defaultFetchGroup = false;
1584:                        } else if (jdoField.defaultFetchGroup != NOT_SET) {
1585:                            fmd.defaultFetchGroup = jdoField.defaultFetchGroup == TRUE;
1586:                        }
1587:                        if (jdoField.embedded != NOT_SET) {
1588:                            fmd.embedded = jdoField.embedded == TRUE;
1589:                        }
1590:                        fmd.jdoCollection = jdoField.collection;
1591:                        fmd.jdoArray = jdoField.array;
1592:                        fmd.jdoMap = jdoField.map;
1593:
1594:                        // process extensions
1595:                        processFieldExtensions(fmd, quiet);
1596:
1597:                        // make sure transactional fields do not end up in the default
1598:                        // fetch group
1599:                        if (fmd.persistenceModifier == PERSISTENCE_MODIFIER_TRANSACTIONAL) {
1600:                            fmd.defaultFetchGroup = false;
1601:                        }
1602:                    } catch (RuntimeException e) {
1603:                        if (quiet) {
1604:                            if (fmd != null)
1605:                                fmd.addError(e, quiet);
1606:                            else
1607:                                cmd.addError(e, quiet);
1608:                            continue;
1609:                        } else {
1610:                            throw e;
1611:                        }
1612:                    }
1613:                }
1614:            }
1615:
1616:            /**
1617:             * Create metadata using reflection.
1618:             * @param cmd
1619:             * @param fieldMap
1620:             */
1621:            private void createFmdWithReflection(ClassMetaData cmd,
1622:                    Map fieldMap, String prefix) {
1623:                ClassMetaData.FieldInfo[] fa = cmd.getDeclaredFields();
1624:                for (int i = fa.length - 1; i >= 0; i--) {
1625:                    ClassMetaData.FieldInfo f = fa[i];
1626:                    String fname = f.getName();
1627:
1628:                    if (mdutils.isEnhancerAddedField(fname))
1629:                        continue;
1630:
1631:                    FieldMetaData fmd = new FieldMetaData();
1632:                    fmd.classMetaData = cmd;
1633:                    fmd.name = prefix + fname;
1634:                    fmd.origName = fname;
1635:                    fmd.setType(f.getType());
1636:                    fmd.setComponentType(fmd.type.getComponentType());
1637:                    fmd.modifiers = f.getModifiers();
1638:                    fmd.scoField = mdutils.isMutableType(fmd.type);
1639:                    if (mdutils.isDefaultPersistentField(f,
1640:                            classAndInterfaceMap)) {
1641:                        fmd.persistenceModifier = PERSISTENCE_MODIFIER_PERSISTENT;
1642:                    } else {
1643:                        fmd.persistenceModifier = PERSISTENCE_MODIFIER_NONE;
1644:                    }
1645:                    fmd.nullValue = NULL_VALUE_NONE;
1646:                    fmd.defaultFetchGroupDefault = mdutils
1647:                            .isDefaultFetchGroupType(fmd.type);
1648:                    fmd.defaultFetchGroup = fmd.defaultFetchGroupDefault;
1649:                    fmd.embedded = mdutils.isEmbeddedType(fmd.type);
1650:                    fieldMap.put(fmd.name, fmd);
1651:                }
1652:            }
1653:
1654:            /**
1655:             * The supplied 'fields' list must be sorted on the natural ordering of fmd's.
1656:             */
1657:            private void finalizeFmds(List fields, ClassMetaData cmd,
1658:                    boolean quiet) {
1659:                // create our fields array
1660:                FieldMetaData[] fmda = cmd.fields = new FieldMetaData[fields
1661:                        .size()];
1662:                fields.toArray(fmda);
1663:                cmd.realFieldCount = fmda.length;
1664:
1665:                // set the fieldNo for each field
1666:                for (int i = fmda.length - 1; i >= 0; i--) {
1667:                    fmda[i].fieldNo = i;
1668:                }
1669:
1670:                // process all subclasses
1671:                ClassMetaData[] pcSubclasses = cmd.pcSubclasses;
1672:                if (pcSubclasses != null) {
1673:                    int len = pcSubclasses.length;
1674:                    for (int i = 0; i < len; i++) {
1675:                        createFieldMetaDataImp(pcSubclasses[i], quiet);
1676:                    }
1677:                }
1678:                updateScoFields(cmd);
1679:            }
1680:
1681:            private void updateScoFields(ClassMetaData cmd) {
1682:                FieldMetaData fmd;
1683:                for (int i = 0; i < cmd.fields.length; i++) {
1684:                    fmd = cmd.fields[i];
1685:                    if (fmd.category == MDStatics.CATEGORY_ARRAY
1686:                            || fmd.category == MDStatics.CATEGORY_COLLECTION
1687:                            || fmd.category == MDStatics.CATEGORY_MAP
1688:
1689:                            || fmd.typeCode == MDStatics.DATE) {
1690:                        fmd.setScoField(true);
1691:                        setSCOFactory(fmd);
1692:                    }
1693:                }
1694:            }
1695:
1696:            /**
1697:             * Process the extensions for fmd (if any).
1698:             */
1699:            private void processFieldExtensions(FieldMetaData fmd, boolean quite) {
1700:                JdoExtension[] a = fmd.jdoField.extensions;
1701:                if (a == null)
1702:                    return;
1703:                for (int i = 0; i < a.length; i++) {
1704:                    JdoExtension e = a[i];
1705:                    switch (e.key) {
1706:                    case JdoExtensionKeys.NULL_INDICATOR:
1707:                        fmd.embedded = true;
1708:                        break;
1709:                    case JdoExtensionKeys.FIELD:
1710:                        fmd.embedded = true;
1711:                        break;
1712:                    case JdoExtensionKeys.EXTERNALIZER:
1713:                        fmd.category = MDStatics.CATEGORY_EXTERNALIZED;
1714:                        try {
1715:                            fmd.externalizer = createExternalizer(fmd.type, e);
1716:                        } catch (RuntimeException x) {
1717:                            fmd.addError(x, quiet);
1718:                        }
1719:                        break;
1720:                    case JdoExtensionKeys.NULL_IF_NOT_FOUND:
1721:                        fmd.nullIfNotFound = e.getBoolean();
1722:                        break;
1723:                    case JdoExtensionKeys.DEPENDENT:
1724:                        fmd.dependentValues = e.getBoolean();
1725:                        break;
1726:                    case JdoExtensionKeys.KEYS_DEPENDENT:
1727:                        fmd.dependentKeys = e.getBoolean();
1728:                        break;
1729:                    case JdoExtensionKeys.AUTOSET:
1730:                        int v = e.getEnum(MDE.AUTOSET_ENUM);
1731:                        int tc = fmd.typeCode;
1732:                        if (v != AUTOSET_NO && tc != DATE && tc != INT
1733:                                && tc != SHORT && tc != BYTE) {
1734:                            RuntimeException ex = BindingSupportImpl
1735:                                    .getInstance()
1736:                                    .runtime(
1737:                                            "The autoset extension "
1738:                                                    + "may only be used on java.util.Date, int, short and byte fields\n"
1739:                                                    + e.getContext());
1740:                            fmd.addError(ex, quite);
1741:                        }
1742:                        fmd.setAutoSet(v);
1743:                        break;
1744:                    case JdoExtensionKeys.NULL_VALUE:
1745:                    case JdoExtensionKeys.FETCH_GROUP:
1746:                    case JdoExtensionKeys.VALID_CLASS:
1747:                        // these are handled later
1748:                        break;
1749:                    case JdoExtensionKeys.SCO_FACTORY:
1750:                        try {
1751:                            Class factoryClass = ClassHelper.get()
1752:                                    .classForName(e.value, false, loader);
1753:                            Object factory = factoryClass.newInstance();
1754:                            fmd.setScoFactory(factory);
1755:                        } catch (Exception ex) {
1756:                            RuntimeException exception = BindingSupportImpl
1757:                                    .getInstance().runtime(
1758:                                            "Unable to add SCO factory mapping:\n"
1759:                                                    + ex.getMessage(), ex);
1760:                            fmd.addError(exception, quite);
1761:                        }
1762:                        break;
1763:                    default:
1764:                        if (e.isCommon()) {
1765:                            RuntimeException ex = BindingSupportImpl
1766:                                    .getInstance().runtime(
1767:                                            "Unexpected extension\n "
1768:                                                    + e.getContext());
1769:                            fmd.addError(ex, quite);
1770:                        }
1771:                    }
1772:                }
1773:            }
1774:
1775:            /**
1776:             * Convert a meta data type name (int, String, Integer, za.co.hemtech.Blah
1777:             * etc.) into a Class.
1778:             *
1779:             * @param name    The name as in the meta data (e.g. Blah)
1780:             * @param qname   The name with package added (e.g. za.co.hemtech.Blah)
1781:             * @param descr   Description of name for error messages (e.g. value-class)
1782:             * @param context Element to supply context for error messages
1783:             * @return Class or null if name is not found and qname is null
1784:             */
1785:            private Class resolveTypeName(String name, String qname,
1786:                    String descr, JdoElement context) {
1787:                Class type = MDStaticUtils.toSimpleClass(name);
1788:                if (type == null) {
1789:                    try {
1790:                        if (name.endsWith(ARRAY_SUFFIX)) {
1791:                            return Array.newInstance(
1792:                                    resolveTypeName(name.substring(0, name
1793:                                            .length()
1794:                                            - ARRAY_SUFFIX.length()), qname
1795:                                            .substring(0, qname.length()
1796:                                                    - ARRAY_SUFFIX.length()),
1797:                                            descr, context), 0).getClass();
1798:                        } else {
1799:                            type = loadClass(name);
1800:                        }
1801:                    } catch (ClassNotFoundException e) {
1802:                        //ignore
1803:                    }
1804:                    if (qname != null) {
1805:                        try {
1806:                            type = loadClass(qname);
1807:                        } catch (ClassNotFoundException e) {
1808:                            throw BindingSupportImpl.getInstance().runtime(
1809:                                    descr + " class not found: " + qname + "\n"
1810:                                            + context.getContext(), e);
1811:                        }
1812:                    }
1813:                }
1814:                return type;
1815:            }
1816:
1817:            /**
1818:             * Fill in collection, array or map related fields for the meta data.
1819:             */
1820:            private void fillCollectionMetaData(FieldMetaData fmd) {
1821:                String msg = null;
1822:                JdoExtension[] extensions = null;
1823:                Class t;
1824:                switch (fmd.category) {
1825:                case CATEGORY_COLLECTION:
1826:                    if (fmd.jdoArray != null) {
1827:                        msg = "array";
1828:                    } else if (fmd.jdoMap != null)
1829:                        msg = "map";
1830:                    if (msg != null)
1831:                        break;
1832:                    fmd.ordered = List.class.isAssignableFrom(fmd.type)
1833:
1834:                    ;
1835:                    fmd.setElementType(Object.class);
1836:                    JdoCollection col = fmd.jdoCollection;
1837:                    if (col != null) {
1838:                        extensions = col.extensions;
1839:                        t = resolveTypeName(col.elementType, col
1840:                                .getElementTypeQName(), "element-type", col);
1841:                    } else {
1842:                        t = null;
1843:                        extensions = null;
1844:                    }
1845:                    if (t == null) {
1846:                        t = MetaDataUtils.getGenericElementType(fmd
1847:                                .getReflectField());
1848:                        if (t == null)
1849:                            t = Object.class;
1850:                    }
1851:
1852:                    fmd.setElementType(t);
1853:                    fmd.elementTypeMetaData = (ClassMetaData) classMap
1854:                            .get(fmd.elementType);
1855:                    if (col != null && col.embeddedElement != NOT_SET) {
1856:                        fmd.embeddedElement = col.embeddedElement == TRUE;
1857:                    }
1858:                    break;
1859:
1860:                case CATEGORY_ARRAY:
1861:                    if (fmd.jdoCollection != null) {
1862:                        msg = "collection";
1863:                    } else if (fmd.jdoMap != null)
1864:                        msg = "map";
1865:                    if (msg != null)
1866:                        break;
1867:                    fmd.ordered = true;
1868:                    fmd.setElementType(fmd.componentType);
1869:                    fmd.elementTypeMetaData = (ClassMetaData) classMap
1870:                            .get(fmd.elementType);
1871:                    JdoArray ar = fmd.jdoArray;
1872:                    if (ar != null) {
1873:                        extensions = ar.extensions;
1874:                        if (ar.embeddedElement != NOT_SET) {
1875:                            fmd.embeddedElement = ar.embeddedElement == TRUE;
1876:                        }
1877:                    }
1878:                    break;
1879:
1880:                case CATEGORY_MAP:
1881:                    if (fmd.jdoArray != null) {
1882:                        msg = "array";
1883:                    } else if (fmd.jdoCollection != null)
1884:                        msg = "collection";
1885:                    if (msg != null)
1886:                        break;
1887:                    fmd.setElementType(Object.class);
1888:                    fmd.setKeyType(Object.class);
1889:                    JdoMap map = fmd.jdoMap;
1890:                    extensions = map == null ? null : map.extensions;
1891:                    if (map != null) {
1892:                        t = resolveTypeName(map.valueType, map
1893:                                .getValueTypeQName(), "value-type", map);
1894:                        extensions = map.extensions;
1895:                    } else {
1896:                        t = null;
1897:                        extensions = null;
1898:                    }
1899:                    if (t == null) {
1900:                        t = MetaDataUtils.getGenericValueType(fmd
1901:                                .getReflectField());
1902:                        if (t == null)
1903:                            t = Object.class;
1904:                    }
1905:                    fmd.setElementType(t);
1906:                    fmd.elementTypeMetaData = (ClassMetaData) classMap
1907:                            .get(fmd.elementType);
1908:                    if (map != null && map.embeddedValue != NOT_SET) {
1909:                        fmd.embeddedElement = map.embeddedValue == TRUE;
1910:                    }
1911:                    if (map != null) {
1912:                        t = resolveTypeName(map.keyType, map.getKeyTypeQName(),
1913:                                "key-type", map);
1914:                    } else {
1915:                        t = null;
1916:                    }
1917:                    if (t == null) {
1918:                        t = MetaDataUtils.getGenericKeyType(fmd
1919:                                .getReflectField());
1920:                        if (t == null)
1921:                            t = Object.class;
1922:                    }
1923:                    fmd.setKeyType(t);
1924:                    fmd.keyTypeMetaData = (ClassMetaData) classMap
1925:                            .get(fmd.keyType);
1926:                    if (map != null && map.embeddedKey != NOT_SET) {
1927:                        fmd.embeddedKey = map.embeddedKey == TRUE;
1928:                    }
1929:                    break;
1930:                }
1931:                if (msg != null) {
1932:                    throw BindingSupportImpl.getInstance().runtime(
1933:                            "Element <" + msg + "> is "
1934:                                    + "not allowed for field " + fmd.name
1935:                                    + "\n" + fmd.jdoField.getContext());
1936:                }
1937:
1938:                // if field has dependent=true check that this is ok
1939:                switch (fmd.category) {
1940:                case CATEGORY_COLLECTION:
1941:                case CATEGORY_ARRAY:
1942:                case CATEGORY_MAP:
1943:                    // if dependent is true then the element/value must be PC class
1944:                    if (!fmd.dependentValues || fmd.isElementTypePC())
1945:                        break;
1946:                default:
1947:                    if (fmd.category == CATEGORY_REF
1948:                            || fmd.category == CATEGORY_POLYREF
1949:                            || !fmd.dependentValues) {
1950:                        break;
1951:                    }
1952:                    throw BindingSupportImpl
1953:                            .getInstance()
1954:                            .runtime(
1955:                                    "The dependent extension is only valid for "
1956:                                            + "references, collections and maps of persistent classes\n"
1957:                                            + fmd.jdoField.getContext());
1958:                }
1959:
1960:                // if field keys-dependent=true check that this is ok
1961:                if (fmd.category == CATEGORY_MAP) {
1962:                    // if keys-dependent is true then the key must be PC class
1963:                    if (fmd.dependentKeys && fmd.keyTypeMetaData == null) {
1964:                        throw BindingSupportImpl.getInstance().runtime(
1965:                                "The keys-dependent extension is only valid for "
1966:                                        + "maps with a persistent class key\n"
1967:                                        + fmd.jdoField.getContext());
1968:                    }
1969:                } else if (fmd.dependentKeys) {
1970:                    throw BindingSupportImpl.getInstance().runtime(
1971:                            "The keys-dependent extension is only valid for maps\n"
1972:                                    + fmd.jdoField.getContext());
1973:                }
1974:
1975:                // process extensions
1976:                if (extensions != null) {
1977:                    int n = extensions.length;
1978:                    JdoExtension ordered = null;
1979:                    JdoExtension ordering = null;
1980:                    for (int i = 0; i < n; i++) {
1981:                        JdoExtension e = extensions[i];
1982:                        switch (e.key) {
1983:                        case JdoExtensionKeys.ORDERED:
1984:                            if (!fmd.ordered) {
1985:                                throw BindingSupportImpl.getInstance().runtime(
1986:                                        "The ordered extension is not allowed here\n"
1987:                                                + e.getContext());
1988:                            }
1989:                            ordered = e;
1990:                            break;
1991:                        case JdoExtensionKeys.ORDERING:
1992:                            ordering = e;
1993:                            break;
1994:                        case JdoExtensionKeys.MANAGED:
1995:                            // this is processed later by the JdbcMetaDataBuilder
1996:                            break;
1997:                        default:
1998:                            if (e.isCommon()) {
1999:                                throw BindingSupportImpl.getInstance().runtime(
2000:                                        "Unexpected extension\n"
2001:                                                + e.getContext());
2002:                            }
2003:                        }
2004:                    }
2005:                    if (ordered != null)
2006:                        fmd.ordered = ordered.getBoolean();
2007:                    if (ordering != null) {
2008:                        if (ordered != null && ordered.getBoolean()) {
2009:                            throw BindingSupportImpl.getInstance().runtime(
2010:                                    "You may not specify an ordering if you also have ordered=true\n"
2011:                                            + ordering.getContext());
2012:                        }
2013:                        fmd.ordered = false;
2014:                        try {
2015:                            fmd.ordering = queryParser.parseOrdering(
2016:                                    fmd.elementTypeMetaData, ordering
2017:                                            .getString());
2018:                        } catch (ParseException e) {
2019:                            throw BindingSupportImpl.getInstance().runtime(
2020:                                    "Invalid ordering extension: "
2021:                                            + e.getMessage() + "\n"
2022:                                            + ordering.getContext() + "\n", e);
2023:                        }
2024:                    }
2025:                }
2026:            }
2027:
2028:            /**
2029:             * Fill in collection, array or map related fields for the meta data.
2030:             */
2031:            private void setSCOFactory(FieldMetaData fmd) {
2032:                if (fmd.checkCustomFactory()) {
2033:                    return;
2034:                }
2035:                if (fmd.scoField) {
2036:                    switch (fmd.category) {
2037:                    case CATEGORY_SIMPLE:
2038:                        if (fmd.simpleSCOFactory == null) {
2039:                            fmd.simpleSCOFactory = scoFactoryRegistry
2040:                                    .getJdoGenieSCOFactory(fmd);
2041:                        }
2042:                        break;
2043:                    case CATEGORY_COLLECTION:
2044:                        if (fmd.collectionFactory == null) {
2045:                            fmd.collectionFactory = scoFactoryRegistry
2046:                                    .getJDOGenieSCOCollectionFactory(fmd);
2047:                        }
2048:                        break;
2049:                    case CATEGORY_MAP:
2050:                        if (fmd.mapFactory == null) {
2051:                            fmd.mapFactory = scoFactoryRegistry
2052:                                    .getJDOGenieSCOMapFactory(fmd);
2053:                        }
2054:                        break;
2055:                    }
2056:                }
2057:            }
2058:
2059:            /**
2060:             * Get the ClassInfo for cmd. A new ClassInfo will be created if none
2061:             * exists.
2062:             */
2063:            private ClassInfo getClassInfo(ClassMetaData cmd) {
2064:                ClassInfo ans = (ClassInfo) classInfoMap.get(cmd);
2065:                if (ans == null)
2066:                    classInfoMap.put(cmd, ans = new ClassInfo());
2067:                return ans;
2068:            }
2069:
2070:            /**
2071:             * Fill the externalizerMap from the configuration.
2072:             */
2073:            private void fillExternalizerMap() {
2074:                externalizerMap.clear();
2075:                int n = config.externalizers.size();
2076:                for (int i = 0; i < n; i++) {
2077:                    ConfigInfo.ExternalizerInfo ei = (ConfigInfo.ExternalizerInfo) config.externalizers
2078:                            .get(i);
2079:                    if (!ei.enabled)
2080:                        continue;
2081:                    try {
2082:                        Class key = loadClass(ei.typeName);
2083:                        Class cls = loadExternalizerClass(ei.externalizerName);
2084:                        externalizerMap.put(key, createExternalizer(cls, key,
2085:                                ei.args));
2086:                        mdutils.registerExternalizedType(key);
2087:                    } catch (Throwable x) {
2088:                        RuntimeException e;
2089:                        if (BindingSupportImpl.getInstance().isOwnException(x)) {
2090:                            e = (RuntimeException) x;
2091:                        } else {
2092:                            e = BindingSupportImpl.getInstance().runtime(
2093:                                    "Unable to create Externalizer for '"
2094:                                            + ei.typeName + "':\n"
2095:                                            + x.toString(), x);
2096:                        }
2097:                        jmd.addError(e, quiet);
2098:                    }
2099:                }
2100:            }
2101:
2102:            private Externalizer createExternalizer(Class externalizerCls,
2103:                    Class type, Map props) throws IllegalAccessException,
2104:                    InstantiationException, InvocationTargetException {
2105:                Externalizer externalizer;
2106:                try {
2107:                    Constructor m = externalizerCls
2108:                            .getConstructor(new Class[] { Class.class });
2109:                    externalizer = (Externalizer) m
2110:                            .newInstance(new Object[] { type });
2111:                } catch (NoSuchMethodException e) {
2112:                    externalizer = (Externalizer) externalizerCls.newInstance();
2113:                }
2114:                BeanUtils.setProperties(externalizer, props);
2115:                return externalizer;
2116:            }
2117:
2118:            /**
2119:             * Load an externalizer class. This will recognize the short names of
2120:             * the built in externalizers and returns the default externalizer for
2121:             * a null name.
2122:             */
2123:            private Class loadExternalizerClass(String name)
2124:                    throws ClassNotFoundException {
2125:                if (name == null
2126:                        || SerializedExternalizer.SHORT_NAME.equals(name)) {
2127:                    return SerializedExternalizer.class;
2128:                } else if (TypeAsBytesExternalizer.SHORT_NAME.equals(name)) {
2129:                    return TypeAsBytesExternalizer.class;
2130:                } else if (TypeAsStringExternalizer.SHORT_NAME.equals(name)) {
2131:                    return TypeAsStringExternalizer.class;
2132:                }
2133:                return loadClass(name);
2134:            }
2135:
2136:            /**
2137:             * Get a externalizer instance for a field type or Serializing Externalizer if null.
2138:             */
2139:            private Externalizer getExternalizerForType(Class type) {
2140:                Externalizer ex = (Externalizer) externalizerMap.get(type);
2141:                if (ex == null && Serializable.class.isAssignableFrom(type)) {
2142:                    try {
2143:                        ex = createExternalizer(SerializedExternalizer.class,
2144:                                type, null);
2145:                    } catch (Exception e) {
2146:                        throw BindingSupportImpl.getInstance().internal(
2147:                                e.getMessage(), e);
2148:                    }
2149:                }
2150:                return ex;
2151:            }
2152:
2153:            /**
2154:             * Create a Externalizer instance from an extension. This will return
2155:             * instances of standard externalizers if their SHORT_NAME's are used.
2156:             */
2157:            private Externalizer createExternalizer(Class type, JdoExtension e) {
2158:                try {
2159:                    String cname = e.getString();
2160:                    Class cls = loadExternalizerClass(cname);
2161:                    return createExternalizer(cls, type, e.getPropertyMap());
2162:                } catch (Throwable x) {
2163:                    x = BindingSupportImpl.getInstance().findCause(x);
2164:                    if (BindingSupportImpl.getInstance().isOwnException(x)) {
2165:                        throw (RuntimeException) x;
2166:                    }
2167:                    throw BindingSupportImpl.getInstance().runtime(
2168:                            x.toString(), x);
2169:                }
2170:            }
2171:
2172:            /**
2173:             * Should the current state information be sent with a request to load
2174:             * any fetch group containing secondary fields?
2175:             */
2176:            public boolean isSendCurrentForFGWithSecFields() {
2177:                return false;
2178:            }
2179:
2180:            /**
2181:             * When writing to an object must it be completely read first?
2182:             */
2183:            public boolean isReadObjectBeforeWrite() {
2184:                return false;
2185:            }
2186:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.