Source Code Cross Referenced for ClassMetaData.java in  » Database-ORM » TJDO » com » triactive » jdo » model » 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 » Database ORM » TJDO » com.triactive.jdo.model 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2004 (C) TJDO.
003:         * All rights reserved.
004:         *
005:         * This software is distributed under the terms of the TJDO License version 1.0.
006:         * See the terms of the TJDO License in the documentation provided with this software.
007:         *
008:         * $Id: ClassMetaData.java,v 1.10 2004/01/18 03:01:06 jackknifebarber Exp $
009:         */
010:
011:        package com.triactive.jdo.model;
012:
013:        import com.triactive.jdo.ClassNotPersistenceCapableException;
014:        import com.triactive.jdo.util.MacroString;
015:        import com.triactive.jdo.util.XMLHelper;
016:        import java.lang.reflect.Field;
017:        import java.lang.reflect.Modifier;
018:        import java.net.URL;
019:        import java.util.Arrays;
020:        import java.util.ArrayList;
021:        import java.util.Collections;
022:        import java.util.HashMap;
023:        import java.util.HashSet;
024:        import java.util.Iterator;
025:        import java.util.List;
026:        import java.util.Map;
027:        import java.util.Set;
028:        import java.util.WeakHashMap;
029:        import javax.jdo.JDOFatalInternalException;
030:        import javax.jdo.JDOFatalUserException;
031:        import javax.jdo.JDOUserException;
032:        import javax.jdo.spi.JDOImplHelper;
033:        import javax.jdo.spi.PersistenceCapable;
034:        import org.w3c.dom.Element;
035:        import org.w3c.dom.Node;
036:        import org.w3c.dom.NodeList;
037:        import org.apache.log4j.Category;
038:
039:        public final class ClassMetaData extends MetaData {
040:            private static final Category LOG = Category
041:                    .getInstance(ClassMetaData.class);
042:
043:            private static Map metaDataByClass = new WeakHashMap();
044:            private static Map searchedPathsByClassLoader = new WeakHashMap();
045:
046:            public static synchronized ClassMetaData forClass(Class c) {
047:                if (c.isArray() || c.isInterface() || c.isPrimitive())
048:                    return null;
049:
050:                if (metaDataByClass.containsKey(c))
051:                    return (ClassMetaData) metaDataByClass.get(c);
052:
053:                ClassLoader cl = c.getClassLoader();
054:
055:                if (cl == null)
056:                    cl = ClassLoader.getSystemClassLoader();
057:
058:                Set searchedPaths = (Set) searchedPathsByClassLoader.get(cl);
059:
060:                if (searchedPaths == null) {
061:                    searchedPaths = new HashSet();
062:                    searchedPathsByClassLoader.put(cl, searchedPaths);
063:                }
064:
065:                ClassMetaData cmd = null;
066:                Iterator i = possiblePathsFor(c).iterator();
067:
068:                while (cmd == null && i.hasNext()) {
069:                    String path = (String) i.next();
070:
071:                    if (!searchedPaths.contains(path)) {
072:                        if (LOG.isDebugEnabled())
073:                            LOG.debug("Searching for metadata at " + path
074:                                    + " using " + cl);
075:
076:                        URL url = cl.getResource(path);
077:
078:                        if (url != null)
079:                            cmd = loadMetadataFileLookingFor(url, c, cl);
080:
081:                        searchedPaths.add(path);
082:                    }
083:                }
084:
085:                if (cmd != null)
086:                    cmd.assertIsValidated();
087:
088:                return cmd;
089:            }
090:
091:            private static List possiblePathsFor(Class c) {
092:                ArrayList paths = new ArrayList();
093:
094:                paths.add("META-INF/package.jdo");
095:                paths.add("WEB-INF/package.jdo");
096:                paths.add("package.jdo");
097:
098:                String path = c.getName().replace('.', '/');
099:
100:                for (int slash = 0; (slash = path.indexOf('/', slash)) >= 0;)
101:                    paths.add(path.substring(0, ++slash) + "package.jdo");
102:
103:                paths.add(path + ".jdo");
104:
105:                /* Add 1.0-style naming convention to the end of the search list. */
106:                for (int slash = path.length() - 1; (slash = path.lastIndexOf(
107:                        '/', slash)) >= 0;)
108:                    paths.add(path.substring(0, slash--) + ".jdo");
109:
110:                return paths;
111:            }
112:
113:            private static ClassMetaData loadMetadataFileLookingFor(URL url,
114:                    Class targetClass, ClassLoader cl) {
115:                if (LOG.isDebugEnabled())
116:                    LOG.debug("Loading metadata from " + url);
117:
118:                ClassMetaData found = null;
119:                Element docElement;
120:
121:                try {
122:                    docElement = XMLHelper.getDocumentBuilder().parse(
123:                            url.openStream()).getDocumentElement();
124:                } catch (Exception e) {
125:                    throw new XMLMetaDataException(url,
126:                            "Could not access or parse metadata file", e);
127:                }
128:
129:                NodeList nodes = docElement.getElementsByTagName("class");
130:
131:                for (int i = 0; i < nodes.getLength(); ++i) {
132:                    Element clsElement = (Element) nodes.item(i);
133:                    String packageName = ((Element) clsElement.getParentNode())
134:                            .getAttribute("name");
135:                    String className = packageName + '.'
136:                            + clsElement.getAttribute("name");
137:                    Class c;
138:
139:                    try {
140:                        /*
141:                         * Important that 'true' is passed here so that each class is
142:                         * initialized.  That's needed so that the static initialization
143:                         * block registers with JDOImplHelper, which will be consulted
144:                         * during ClassMetaData validation.
145:                         */
146:                        c = Class.forName(className, true, cl);
147:                    } catch (ClassNotFoundException e) {
148:                        throw new XMLMetaDataException(url, "Class" + className
149:                                + " not found", e);
150:                    }
151:
152:                    if (!metaDataByClass.containsKey(c)) {
153:                        ClassMetaData cmd = new ClassMetaData(c, url,
154:                                clsElement);
155:                        metaDataByClass.put(c, cmd);
156:
157:                        if (c.equals(targetClass))
158:                            found = cmd;
159:                    }
160:                }
161:
162:                return found;
163:            }
164:
165:            public static final byte NEW = 0, CONSTRUCTED = 1, VALIDATED = 2;
166:
167:            public static final int NO_IDENTITY = 0, DATASTORE_IDENTITY = 1,
168:                    APPLICATION_IDENTITY = 2;
169:
170:            private static final List identityTypeValues = Arrays
171:                    .asList(new String[] { "nondurable", "datastore",
172:                            "application" });
173:
174:            private final Class clazz;
175:            private final ClassLoader loader;
176:            private final String packageName;
177:            private final URL loadedFrom;
178:            private final int identityType;
179:            private final Class identityClass;
180:            private final boolean requiresExtent;
181:            private final Class pcSuperclass;
182:            private final List managedFields = new ArrayList();
183:            private final Map fieldNumbersByName = new HashMap();
184:
185:            private byte state = NEW;
186:            private boolean validating = false;
187:
188:            /* Fields below are only valid after state == VALIDATED. */
189:            private ClassMetaData pcSuperclassMetaData;
190:            private int inheritedFieldCount;
191:            private int totalFieldCount;
192:            private int[] allFieldNumbers;
193:            private int[] transactionalFieldNumbers;
194:            private int[] persistentFieldNumbers;
195:            private int[] defaultFetchGroupFieldNumbers;
196:            private int[] secondClassMutableFieldNumbers;
197:            private boolean[] transactionalFieldFlags;
198:            private boolean[] persistentFieldFlags;
199:            private boolean[] defaultFetchGroupFieldFlags;
200:            private boolean[] secondClassMutableFieldFlags;
201:
202:            private ClassMetaData(Class clazz, URL loadedFrom,
203:                    Element clsElement) {
204:                super (loadedFrom, clsElement);
205:
206:                String className = clazz.getName();
207:                int lastDot = className.lastIndexOf('.');
208:
209:                this .clazz = clazz;
210:                this .loader = clazz.getClassLoader();
211:                this .packageName = lastDot < 0 ? "" : className.substring(0,
212:                        lastDot);
213:                this .loadedFrom = loadedFrom;
214:
215:                /* Process the "identity-type" attribute. */
216:                String idTypeAttr = clsElement.getAttribute("identity-type");
217:
218:                if (idTypeAttr.length() > 0) {
219:                    identityType = identityTypeValues.indexOf(idTypeAttr);
220:
221:                    if (identityType < 0)
222:                        throw new XMLMetaDataException(loadedFrom,
223:                                "Unrecognized identity-type " + idTypeAttr);
224:                } else
225:                    identityType = DATASTORE_IDENTITY;
226:
227:                if (identityType == APPLICATION_IDENTITY) {
228:                    /* Process the "objectid-class" attribute. */
229:                    String objIDClassName = clsElement
230:                            .getAttribute("objectid-class");
231:                    if (objIDClassName.length() == 0)
232:                        throw new XMLMetaDataException(loadedFrom,
233:                                "Missing objectid-class attribute for class "
234:                                        + clazz.getName());
235:
236:                    if (objIDClassName.indexOf('.') < 0)
237:                        objIDClassName = packageName + '.' + objIDClassName;
238:
239:                    try {
240:                        identityClass = Class.forName(objIDClassName, true,
241:                                loader);
242:                    } catch (ClassNotFoundException e) {
243:                        throw new XMLMetaDataException(loadedFrom,
244:                                "Object ID class for class" + clazz.getName()
245:                                        + " not found", e);
246:                    }
247:                } else
248:                    identityClass = null;
249:
250:                /* Process the "requires-extent" attribute. */
251:                String requiresExtentAttr = clsElement
252:                        .getAttribute("requires-extent");
253:                if (requiresExtentAttr.length() > 0)
254:                    requiresExtent = Boolean.valueOf(requiresExtentAttr)
255:                            .booleanValue();
256:                else
257:                    requiresExtent = true;
258:
259:                /* Process the "persistence-capable-superclass" attribute. */
260:                String pcSuperclassName = clsElement
261:                        .getAttribute("persistence-capable-superclass");
262:                if (pcSuperclassName.length() > 0) {
263:                    Class c;
264:
265:                    try {
266:                        c = Class.forName(pcSuperclassName, true, loader);
267:                    } catch (ClassNotFoundException e) {
268:                        try {
269:                            c = Class.forName(packageName + '.'
270:                                    + pcSuperclassName, true, loader);
271:                        } catch (ClassNotFoundException e1) {
272:                            throw new XMLMetaDataException(loadedFrom,
273:                                    "Class not found", e1);
274:                        }
275:                    }
276:
277:                    pcSuperclass = c;
278:
279:                    if (pcSuperclass.equals(clazz)
280:                            || !pcSuperclass.isAssignableFrom(clazz))
281:                        throw new XMLMetaDataException(loadedFrom,
282:                                "Specified persistence capable superclass "
283:                                        + pcSuperclass.getName()
284:                                        + " is not a superclass of "
285:                                        + clazz.getName());
286:                } else
287:                    pcSuperclass = null;
288:
289:                /* Process "field" child elements. */
290:                for (Node node = clsElement.getFirstChild(); node != null; node = node
291:                        .getNextSibling()) {
292:                    if (node instanceof  Element) {
293:                        Element child = (Element) node;
294:                        String childTag = child.getTagName();
295:
296:                        if (childTag.equals("field"))
297:                            addField(new FieldMetaData(this , child));
298:                    }
299:                }
300:
301:                /*
302:                 * Add any eligible fields that are declared in the class but not in
303:                 * its metadata.
304:                 */
305:                Field declaredFields[] = clazz.getDeclaredFields();
306:
307:                for (int i = 0; i < declaredFields.length; ++i) {
308:                    Field f = declaredFields[i];
309:
310:                    if (!fieldNumbersByName.containsKey(f.getName())) {
311:                        int m = f.getModifiers();
312:
313:                        if (!Modifier.isFinal(m) && !Modifier.isStatic(m)
314:                                && !Modifier.isTransient(m)
315:                                && Types.isDefaultPersistentType(f.getType())) {
316:                            addField(new FieldMetaData(this , f));
317:                        }
318:                    }
319:                }
320:
321:                /*
322:                 * Sort the field list by field name, then create the field name to
323:                 * field number map.
324:                 */
325:                Collections.sort(managedFields);
326:                Iterator iter = managedFields.iterator();
327:
328:                for (int i = 0; iter.hasNext(); ++i) {
329:                    FieldMetaData fmd = (FieldMetaData) iter.next();
330:                    fieldNumbersByName.put(fmd.getName(), new Integer(i));
331:                }
332:
333:                state = CONSTRUCTED;
334:            }
335:
336:            /** Helper method used during only construction. */
337:            private void addField(FieldMetaData fm) {
338:                String name = fm.getName();
339:                if (fieldNumbersByName.containsKey(name))
340:                    throw new DuplicateFieldException(loadedFrom,
341:                            "Duplicate field name " + name + " in class "
342:                                    + clazz.getName());
343:
344:                fieldNumbersByName.put(name, null);
345:
346:                if (fm.getPersistenceModifier() != FieldMetaData.PERSISTENCE_MODIFIER_NONE)
347:                    managedFields.add(fm);
348:            }
349:
350:            private synchronized void assertIsConstructed() {
351:                if (state < CONSTRUCTED)
352:                    throw new JDOFatalInternalException(
353:                            "Object not yet constructed: " + this );
354:            }
355:
356:            public String getJavaName() {
357:                return clazz.getName();
358:            }
359:
360:            public Class getPCClass() {
361:                return clazz;
362:            }
363:
364:            public String getPackageName() {
365:                return packageName;
366:            }
367:
368:            public URL getSourceURL() {
369:                return loadedFrom;
370:            }
371:
372:            public Class getPCSuperclass() {
373:                return pcSuperclass;
374:            }
375:
376:            public int getIdentityType() {
377:                return identityType;
378:            }
379:
380:            public Class getIdentityClass() {
381:                return identityClass;
382:            }
383:
384:            public boolean requiresExtent() {
385:                return requiresExtent;
386:            }
387:
388:            public int getFieldCount() {
389:                assertIsConstructed();
390:                return managedFields.size();
391:            }
392:
393:            public FieldMetaData getFieldRelative(int relativeFieldNumber) {
394:                assertIsConstructed();
395:                return (FieldMetaData) managedFields.get(relativeFieldNumber);
396:            }
397:
398:            public int getRelativeFieldNumber(String name) {
399:                assertIsConstructed();
400:                Integer i = (Integer) fieldNumbersByName.get(name);
401:
402:                return i == null ? -1 : i.intValue();
403:            }
404:
405:            public String getViewImports() {
406:                return getVendorExtension(MY_VENDOR, "view-imports");
407:            }
408:
409:            public String getViewDefinition(String vendorID) {
410:                String viewDef = null;
411:
412:                if (vendorID != null)
413:                    viewDef = getVendorExtension(MY_VENDOR, "view-definition"
414:                            + '-' + vendorID);
415:
416:                if (viewDef == null)
417:                    viewDef = getVendorExtension(MY_VENDOR, "view-definition");
418:
419:                return viewDef;
420:            }
421:
422:            private synchronized boolean assertIsValidated() {
423:                assertIsConstructed();
424:
425:                if (state < VALIDATED) {
426:                    if (validating)
427:                        throw new JDOFatalInternalException(
428:                                "assertIsValidated() called recursively");
429:
430:                    validating = true;
431:
432:                    try {
433:                        validateAgainstClass();
434:                    } finally {
435:                        validating = false;
436:                    }
437:
438:                    return true;
439:                } else
440:                    return false;
441:            }
442:
443:            private void validateAgainstClass() {
444:                /*
445:                 * If the class has already been enhanced, verify that it agrees with
446:                 * the current metadata.
447:                 */
448:                if (Types.isEnhancedClass(clazz)) {
449:                    JDOImplHelper helper = JDOImplHelper.getInstance();
450:                    String[] fieldNames = helper.getFieldNames(clazz);
451:                    Class[] fieldTypes = helper.getFieldTypes(clazz);
452:                    byte[] fieldFlags = helper.getFieldFlags(clazz);
453:
454:                    if (fieldNames.length != managedFields.size())
455:                        throw new ClassMetaDataMismatchException(clazz,
456:                                " class has " + fieldNames.length
457:                                        + " fields, metadata has "
458:                                        + managedFields.size() + " fields");
459:
460:                    for (int i = 0; i < fieldNames.length; ++i) {
461:                        FieldMetaData fmd = (FieldMetaData) managedFields
462:                                .get(i);
463:
464:                        if (!fieldNames[i].equals(fmd.getName()))
465:                            throw new ClassMetaDataMismatchException(clazz,
466:                                    " class has '" + fieldNames[i]
467:                                            + "' for field " + i
468:                                            + ", metadata has '"
469:                                            + fmd.getName() + "'");
470:
471:                        if (!fieldTypes[i].equals(fmd.getType()))
472:                            throw new ClassMetaDataMismatchException(clazz,
473:                                    " class has type "
474:                                            + fieldTypes[i].getName()
475:                                            + " for field " + i
476:                                            + ", metadata has "
477:                                            + fmd.getType().getName());
478:
479:                        /*
480:                         * Verify that our expectations re. the field flags agree with
481:                         * those of the enhanced class.
482:                         *
483:                         * Enhancers are notorious for getting the "default" value for
484:                         * default-fetch-group, i.e. the value to use if nothing is
485:                         * given in the metadata, wrong sometimes.  So for this one case
486:                         * we tolerate a mismatch between enhanced class and metadata
487:                         * and use the setting indicated by the enhanced class.
488:                         */
489:                        byte expectedFlag;
490:                        byte actualFlag = (byte) (fieldFlags[i] & (PersistenceCapable.CHECK_READ
491:                                | PersistenceCapable.CHECK_WRITE
492:                                | PersistenceCapable.MEDIATE_READ | PersistenceCapable.MEDIATE_WRITE));
493:
494:                        if (fmd.getPersistenceModifier() == FieldMetaData.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
495:                            expectedFlag = PersistenceCapable.CHECK_WRITE;
496:                        } else if (fmd.isPrimaryKeyPart()) {
497:                            expectedFlag = PersistenceCapable.MEDIATE_WRITE;
498:                        } else if (fmd.isInDefaultFetchGroup()) {
499:                            expectedFlag = PersistenceCapable.CHECK_READ
500:                                    | PersistenceCapable.CHECK_WRITE;
501:
502:                            /*
503:                             * Metadata says DFG=true.  If the enhanced class disagrees,
504:                             * go with the enhanced class.
505:                             */
506:                            if (actualFlag == (PersistenceCapable.MEDIATE_READ | PersistenceCapable.MEDIATE_WRITE)) {
507:                                LOG
508:                                        .warn(new ClassMetaDataFlagMismatchException(
509:                                                clazz, i, expectedFlag,
510:                                                actualFlag).getMessage()
511:                                                + ": will use the value in class (non-default fetch group)");
512:
513:                                expectedFlag = PersistenceCapable.MEDIATE_READ
514:                                        | PersistenceCapable.MEDIATE_WRITE;
515:                                fmd.setDefaultFetchGroup(false);
516:                            }
517:                        } else {
518:                            expectedFlag = PersistenceCapable.MEDIATE_READ
519:                                    | PersistenceCapable.MEDIATE_WRITE;
520:
521:                            /*
522:                             * Metadata says DFG=false.  If the enhanced class disagrees,
523:                             * go with the enhanced class.
524:                             */
525:                            if (actualFlag == (PersistenceCapable.CHECK_READ | PersistenceCapable.CHECK_WRITE)) {
526:                                LOG
527:                                        .warn(new ClassMetaDataFlagMismatchException(
528:                                                clazz, i, expectedFlag,
529:                                                actualFlag).getMessage()
530:                                                + ": will use the value in class (default fetch group)");
531:
532:                                expectedFlag = PersistenceCapable.CHECK_READ
533:                                        | PersistenceCapable.CHECK_WRITE;
534:                                fmd.setDefaultFetchGroup(true);
535:                            }
536:                        }
537:
538:                        if (expectedFlag != actualFlag)
539:                            throw new ClassMetaDataFlagMismatchException(clazz,
540:                                    i, expectedFlag, actualFlag);
541:                    }
542:                }
543:
544:                if (pcSuperclass != null) {
545:                    pcSuperclassMetaData = forClass(pcSuperclass);
546:
547:                    if (pcSuperclassMetaData == null)
548:                        throw new XMLMetaDataException(loadedFrom,
549:                                "Specified persistence capable superclass "
550:                                        + pcSuperclass.getName()
551:                                        + " is not persistence capable");
552:
553:                    inheritedFieldCount = pcSuperclassMetaData
554:                            .getInheritedFieldCount()
555:                            + pcSuperclassMetaData.getFieldCount();
556:                } else
557:                    inheritedFieldCount = 0;
558:
559:                totalFieldCount = inheritedFieldCount + managedFields.size();
560:                allFieldNumbers = new int[totalFieldCount];
561:                transactionalFieldFlags = new boolean[totalFieldCount];
562:                persistentFieldFlags = new boolean[totalFieldCount];
563:                defaultFetchGroupFieldFlags = new boolean[totalFieldCount];
564:                secondClassMutableFieldFlags = new boolean[totalFieldCount];
565:                int transactionalFieldCount = 0;
566:                int persistentFieldCount = 0;
567:                int defaultFetchGroupFieldCount = 0;
568:                int secondClassMutableFieldCount = 0;
569:
570:                for (int i = 0; i < totalFieldCount; ++i) {
571:                    allFieldNumbers[i] = i;
572:
573:                    FieldMetaData fmd = getFieldAbsoluteInternal(i);
574:
575:                    if (fmd.getPersistenceModifier() == FieldMetaData.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
576:                        transactionalFieldFlags[i] = true;
577:                        ++transactionalFieldCount;
578:                    } else {
579:                        persistentFieldFlags[i] = true;
580:                        ++persistentFieldCount;
581:
582:                        if (fmd.isInDefaultFetchGroup()) {
583:                            defaultFetchGroupFieldFlags[i] = true;
584:                            ++defaultFetchGroupFieldCount;
585:                        }
586:
587:                        if (Types.isSecondClassMutableType(fmd.getType())) {
588:                            secondClassMutableFieldFlags[i] = true;
589:                            ++secondClassMutableFieldCount;
590:                        }
591:                    }
592:                }
593:
594:                transactionalFieldNumbers = new int[transactionalFieldCount];
595:                persistentFieldNumbers = new int[persistentFieldCount];
596:                defaultFetchGroupFieldNumbers = new int[defaultFetchGroupFieldCount];
597:                secondClassMutableFieldNumbers = new int[secondClassMutableFieldCount];
598:
599:                for (int i = 0, txn = 0, per = 0, dfg = 0, scm = 0; i < totalFieldCount; ++i) {
600:                    if (transactionalFieldFlags[i])
601:                        transactionalFieldNumbers[txn++] = i;
602:
603:                    if (persistentFieldFlags[i])
604:                        persistentFieldNumbers[per++] = i;
605:
606:                    if (defaultFetchGroupFieldFlags[i])
607:                        defaultFetchGroupFieldNumbers[dfg++] = i;
608:
609:                    if (secondClassMutableFieldFlags[i])
610:                        secondClassMutableFieldNumbers[scm++] = i;
611:                }
612:
613:                state = VALIDATED;
614:            }
615:
616:            private FieldMetaData getFieldAbsoluteInternal(
617:                    int absoluteFieldNumber) {
618:                if (absoluteFieldNumber < inheritedFieldCount) {
619:                    if (pcSuperclassMetaData == null)
620:                        return null;
621:                    else
622:                        return pcSuperclassMetaData
623:                                .getFieldAbsoluteInternal(absoluteFieldNumber);
624:                } else
625:                    return (FieldMetaData) managedFields
626:                            .get(absoluteFieldNumber - inheritedFieldCount);
627:            }
628:
629:            public int getInheritedFieldCount() {
630:                assertIsValidated();
631:                return inheritedFieldCount;
632:            }
633:
634:            public FieldMetaData getFieldAbsolute(int absoluteFieldNumber) {
635:                assertIsValidated();
636:                return getFieldAbsoluteInternal(absoluteFieldNumber);
637:            }
638:
639:            public int getAbsoluteFieldNumber(String name) {
640:                assertIsValidated();
641:                int lastDot = name.lastIndexOf('.');
642:
643:                if (lastDot >= 0) {
644:                    /* Field name is of the form "com.acme.MyClass.myField". */
645:                    Class c;
646:
647:                    try {
648:                        c = Class.forName(name.substring(0, lastDot), true,
649:                                loader);
650:                    } catch (ClassNotFoundException e) {
651:                        throw new JDOUserException(
652:                                "Class in field name not found: " + name, e);
653:                    }
654:
655:                    ClassMetaData cmd = ClassMetaData.forClass(c);
656:
657:                    if (cmd == null)
658:                        throw new ClassNotPersistenceCapableException(c);
659:
660:                    if (!c.isAssignableFrom(clazz))
661:                        throw new JDOUserException("Class in field name "
662:                                + name + " not compatible with actual class "
663:                                + clazz.getName());
664:
665:                    return cmd.getAbsoluteFieldNumber(name
666:                            .substring(lastDot + 1));
667:                } else {
668:                    /* Field name is of the form "myField" */
669:                    int i = getRelativeFieldNumber(name);
670:
671:                    if (i < 0) {
672:                        if (pcSuperclassMetaData != null)
673:                            i = pcSuperclassMetaData
674:                                    .getAbsoluteFieldNumber(name);
675:                    } else
676:                        i += inheritedFieldCount;
677:
678:                    return i;
679:                }
680:            }
681:
682:            public int[] getAllFieldNumbers() {
683:                assertIsValidated();
684:                return allFieldNumbers;
685:            }
686:
687:            public int[] getTransactionalFieldNumbers() {
688:                assertIsValidated();
689:                return transactionalFieldNumbers;
690:            }
691:
692:            public int[] getPersistentFieldNumbers() {
693:                assertIsValidated();
694:                return persistentFieldNumbers;
695:            }
696:
697:            public int[] getDefaultFetchGroupFieldNumbers() {
698:                assertIsValidated();
699:                return defaultFetchGroupFieldNumbers;
700:            }
701:
702:            public int[] getSecondClassMutableFieldNumbers() {
703:                assertIsValidated();
704:                return secondClassMutableFieldNumbers;
705:            }
706:
707:            public boolean[] getTransactionalFieldFlags() {
708:                assertIsValidated();
709:                return transactionalFieldFlags;
710:            }
711:
712:            public boolean[] getPersistentFieldFlags() {
713:                assertIsValidated();
714:                return persistentFieldFlags;
715:            }
716:
717:            public boolean[] getDefaultFetchGroupFieldFlags() {
718:                assertIsValidated();
719:                return defaultFetchGroupFieldFlags;
720:            }
721:
722:            public boolean[] getSecondClassMutableFieldFlags() {
723:                assertIsValidated();
724:                return secondClassMutableFieldFlags;
725:            }
726:
727:            public List getReferencedClasses(String vendorID) {
728:                Set referenced = new HashSet();
729:                List orderedMetaData = new ArrayList();
730:
731:                getReferencedClasses(vendorID, orderedMetaData, referenced);
732:
733:                return orderedMetaData;
734:            }
735:
736:            /**
737:             * Get the ordered <code>ClassMetaData</code>s for classes referenced
738:             * from this <code>ClassMetaData</code>.  This will add the
739:             * <code>ClassMetaData</code>s to <code>orderedCmds</code> ordered by
740:             * dependency, and to <code>referenced</code> for fast lookups.
741:             * <p>
742:             * This method uses recursion to add all referenced
743:             * <code>ClassMetaData</code> for any fields, identity classes,
744:             * super classes, and classes referenced by a view definition.
745:             * 
746:             * @param vendorID    The vendorID for the database.  This is used to
747:             *   get the appropriate view definition.
748:             * @param orderedCmds A List that all ordered <code>ClassMetaData</code>s
749:             *   will be added to.
750:             * @param referenced  A Set that all <code>ClassMetaData</code>s are
751:             *   added to.  This is used for fast lookups with contains().
752:             */
753:            void getReferencedClasses(final String vendorID,
754:                    final List orderedCmds, final Set referenced) {
755:                assertIsValidated();
756:                Map viewReferences = new HashMap();
757:                getReferencedClasses(vendorID, orderedCmds, referenced,
758:                        viewReferences);
759:            }
760:
761:            /**
762:             * Get the ordered <code>ClassMetaData</code>s for classes referenced
763:             * from this <code>ClassMetaData</code>.  This will add the
764:             * <code>ClassMetaData</code>s to <code>orderedCmds</code> ordered by
765:             * dependency, and to <code>referenced</code> for fast lookups.
766:             * <p>
767:             * This method uses recursion to add all referenced
768:             * <code>ClassMetaData</code> for any fields, identity classes,
769:             * super classes, and classes referenced by a view definition.
770:             * 
771:             * @param vendorID    The vendorID for the database.  This is used to
772:             *   get the appropriate view definition.
773:             * @param orderedCmds A List that all ordered <code>ClassMetaData</code>s
774:             *   will be added to.
775:             * @param referenced  A Set that all <code>ClassMetaData</code>s are
776:             *   added to.  This is used for fast lookups with contains().
777:             * @param viewReferences  A Map mapping Class to a Set of referenced
778:             *   classes for all views.
779:             */
780:            private void getReferencedClasses(final String vendorID,
781:                    final List orderedCmds, final Set referenced,
782:                    final Map viewReferences) {
783:                /*
784:                 * Recursively call getReferencedClasses(...) before adding them
785:                 * to the orderedCmds and referenced.  This will ensure that any
786:                 * classes with dependencies on them are put in the orderedCmds List
787:                 * in the correct order.
788:                 */
789:                if (!referenced.contains(this )) {
790:                    /*
791:                     * Go ahead and add this class to the referenced Set, it will
792:                     * get added to the orderedCmds List after all classes that this
793:                     * depends on have been added.
794:                     */
795:                    referenced.add(this );
796:
797:                    Iterator iter = managedFields.iterator();
798:
799:                    while (iter.hasNext()) {
800:                        FieldMetaData fmd = (FieldMetaData) iter.next();
801:                        fmd.getReferencedClasses(vendorID, orderedCmds,
802:                                referenced);
803:                    }
804:
805:                    if (pcSuperclass != null) {
806:                        forClass(pcSuperclass).getReferencedClasses(vendorID,
807:                                orderedCmds, referenced);
808:                    }
809:
810:                    if (identityClass != null) {
811:                        ClassMetaData icmd = forClass(identityClass);
812:                        if (icmd != null)
813:                            icmd.getReferencedClasses(vendorID, orderedCmds,
814:                                    referenced);
815:                    }
816:
817:                    if (getViewDefinition(vendorID) != null) {
818:                        MacroString viewDef = new MacroString(this .clazz,
819:                                getViewImports(), getViewDefinition(vendorID));
820:                        viewDef
821:                                .substituteMacros(new MacroString.MacroHandler() {
822:                                    public void onIdentifierMacro(
823:                                            MacroString.IdentifierMacro im) {
824:                                        addViewReference(viewReferences,
825:                                                im.clazz);
826:                                        forClass(im.clazz)
827:                                                .getReferencedClasses(vendorID,
828:                                                        orderedCmds,
829:                                                        referenced,
830:                                                        viewReferences);
831:                                    }
832:
833:                                    public void onParameterMacro(
834:                                            MacroString.ParameterMacro pm) {
835:                                        throw new JDOUserException(
836:                                                "Parameter macros not allowed in view definitions: "
837:                                                        + pm);
838:                                    }
839:                                });
840:                    }
841:
842:                    orderedCmds.add(this );
843:                }
844:            }
845:
846:            /**
847:             * Add a reference from this class to the referenced class.  Check the
848:             * view references for circular dependencies.  If there are any circular
849:             * dependencies, throw a JDOUserException.
850:             * @param viewReferences  The Map of Class to Set of referenced Classes
851:             *                        to add the reference to.
852:             * @exception JDOFatalUserException  If a circular reference is found in
853:             *         the view definitions.
854:             */
855:            private void addViewReference(Map viewReferences, Class referenced)
856:                    throws JDOFatalUserException {
857:                if (this .clazz != referenced) {
858:                    /*
859:                     * Add this reference to the Map.
860:                     */
861:                    Set referencedSet = (Set) viewReferences.get(this .clazz);
862:                    if (null == referencedSet) {
863:                        referencedSet = new HashSet();
864:                        viewReferences.put(this .clazz, referencedSet);
865:                    }
866:
867:                    referencedSet.add(referenced);
868:
869:                    /*
870:                     * Check to see if there is a circular dependency.  This will
871:                     * be true if the referenced class references this class.
872:                     */
873:                    checkForCircularReferences(viewReferences, this .clazz,
874:                            referenced, null);
875:                }
876:            }
877:
878:            /**
879:             * Check for any circular references between referencer and referencee.
880:             * If one is found, throw a JDOFatalUserException with the chain of references.
881:             * @param viewReferences   The Map of view references to check.
882:             * @param referencer       The class that has the reference.
883:             * @param referencee       The class that is being referenced.
884:             * @param referenceChain   The List of class that have been referenced so far.
885:             * @exception JDOFatalUserException  If a circular reference is found in
886:             *         the view definitions.
887:             */
888:            private void checkForCircularReferences(Map viewReferences,
889:                    Class referencer, Class referencee, List referenceChain)
890:                    throws JDOFatalUserException {
891:                Set classes = (Set) viewReferences.get(referencee);
892:                if (null != classes) {
893:                    /*
894:                     * Initialize the chain of references if needed.  Add the referencee
895:                     * to the chain.
896:                     */
897:                    if (null == referenceChain) {
898:                        referenceChain = new ArrayList();
899:                        referenceChain.add(referencer);
900:                    }
901:                    referenceChain.add(referencee);
902:
903:                    /*
904:                     * Iterate through all referenced classes from the referencee.  If
905:                     * any reference the referencer, throw an exception.
906:                     */
907:                    for (Iterator it = classes.iterator(); it.hasNext();) {
908:                        Class current = (Class) it.next();
909:
910:                        if (current == referencer) {
911:                            StringBuffer error = new StringBuffer(
912:                                    "A circular dependency exists between views: ");
913:
914:                            for (Iterator chainIter = referenceChain.iterator(); chainIter
915:                                    .hasNext();) {
916:                                error.append(chainIter.next());
917:                                if (chainIter.hasNext()) {
918:                                    error.append(" -> ");
919:                                }
920:                            }
921:
922:                            throw new JDOFatalUserException(error.toString());
923:                        } else {
924:                            /*
925:                             * Make a recursive call to check for any nested dependencies.
926:                             * For example, A references B, B references C, C references A.
927:                             */
928:                            checkForCircularReferences(viewReferences,
929:                                    referencer, current, referenceChain);
930:                        }
931:                    }
932:                }
933:            }
934:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.