Source Code Cross Referenced for PersistCatalog.java in  » JMX » je » com » sleepycat » persist » impl » 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 » JMX » je » com.sleepycat.persist.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*-
002:         * See the file LICENSE for redistribution information.
003:         *
004:         * Copyright (c) 2002,2008 Oracle.  All rights reserved.
005:         *
006:         * $Id: PersistCatalog.java,v 1.33.2.9 2008/01/07 15:14:19 cwl Exp $
007:         */
008:
009:        package com.sleepycat.persist.impl;
010:
011:        import java.io.ByteArrayInputStream;
012:        import java.io.ByteArrayOutputStream;
013:        import java.io.IOException;
014:        import java.io.ObjectInputStream;
015:        import java.io.ObjectOutputStream;
016:        import java.io.Serializable;
017:        import java.util.ArrayList;
018:        import java.util.Collection;
019:        import java.util.HashMap;
020:        import java.util.HashSet;
021:        import java.util.IdentityHashMap;
022:        import java.util.List;
023:        import java.util.Map;
024:        import java.util.NoSuchElementException;
025:        import java.util.Set;
026:
027:        import com.sleepycat.bind.tuple.IntegerBinding;
028:        import com.sleepycat.je.Database;
029:        import com.sleepycat.je.DatabaseConfig;
030:        import com.sleepycat.je.DatabaseEntry;
031:        import com.sleepycat.je.DatabaseException;
032:        import com.sleepycat.je.Environment;
033:        import com.sleepycat.je.OperationStatus;
034:        import com.sleepycat.je.Transaction;
035:        import com.sleepycat.persist.evolve.DeletedClassException;
036:        import com.sleepycat.persist.evolve.IncompatibleClassException;
037:        import com.sleepycat.persist.evolve.Mutations;
038:        import com.sleepycat.persist.evolve.Renamer;
039:        import com.sleepycat.persist.model.AnnotationModel;
040:        import com.sleepycat.persist.model.ClassMetadata;
041:        import com.sleepycat.persist.model.EntityMetadata;
042:        import com.sleepycat.persist.model.EntityModel;
043:        import com.sleepycat.persist.raw.RawObject;
044:        import com.sleepycat.util.RuntimeExceptionWrapper;
045:
046:        /**
047:         * The catalog of class formats for a store, along with its associated model
048:         * and mutations.
049:         *
050:         * @author Mark Hayes
051:         */
052:        public class PersistCatalog implements  Catalog {
053:
054:            /**
055:             * Key to Data record in the catalog database.  In the JE 3.0.12 beta
056:             * version the formatList record is stored under this key and is converted
057:             * to a Data object when it is read.
058:             */
059:            private static final byte[] DATA_KEY = getIntBytes(-1);
060:
061:            /**
062:             * Key to a JE 3.0.12 beta version mutations record in the catalog
063:             * database.  This record is no longer used because mutations are stored in
064:             * the Data record and is deleted when the beta version is detected.
065:             */
066:            private static final byte[] BETA_MUTATIONS_KEY = getIntBytes(-2);
067:
068:            private static byte[] getIntBytes(int val) {
069:                DatabaseEntry entry = new DatabaseEntry();
070:                IntegerBinding.intToEntry(val, entry);
071:                assert entry.getSize() == 4 && entry.getData().length == 4;
072:                return entry.getData();
073:            }
074:
075:            /**
076:             * Used by unit tests.
077:             */
078:            public static boolean expectNoClassChanges;
079:            public static boolean unevolvedFormatsEncountered;
080:
081:            /**
082:             * The object stored under DATA_KEY in the catalog database.
083:             */
084:            private static class Data implements  Serializable {
085:
086:                static final long serialVersionUID = 7515058069137413261L;
087:
088:                List<Format> formatList;
089:                Mutations mutations;
090:                int version;
091:            }
092:
093:            /**
094:             * A list of all formats indexed by formatId.  Element zero is unused and
095:             * null, since IDs start at one; this avoids adjusting the ID to index the
096:             * list.  Some elements are null to account for predefined IDs that are not
097:             * used.
098:             *
099:             * <p>This field, like formatMap, is volatile because it is reassigned
100:             * when dynamically adding new formats.  See {@link getFormat(Class)}.</p>
101:             */
102:            private volatile List<Format> formatList;
103:
104:            /**
105:             * A map of the current/live formats in formatList, indexed by class name.
106:             *
107:             * <p>This field, like formatList, is volatile because it is reassigned
108:             * when dynamically adding new formats.  See {@link getFormat(Class)}.</p>
109:             */
110:            private volatile Map<String, Format> formatMap;
111:
112:            /**
113:             * A map of the latest formats (includes deleted formats) in formatList,
114:             * indexed by class name.
115:             *
116:             * <p>This field, like formatMap, is volatile because it is reassigned
117:             * when dynamically adding new formats.  See {@link getFormat(Class)}.</p>
118:             */
119:            private volatile Map<String, Format> latestFormatMap;
120:
121:            /**
122:             * A temporary map of proxied class name to proxy class name.  Used during
123:             * catalog creation, and then set to null.  This map is used to force proxy
124:             * formats to be created prior to proxied formats. [#14665]
125:             */
126:            private Map<String, String> proxyClassMap;
127:
128:            private boolean rawAccess;
129:            private EntityModel model;
130:            private Mutations mutations;
131:            private Database db;
132:            private int openCount;
133:
134:            /**
135:             * The Store is normally present but may be null in unit tests (for
136:             * example, BindingTest).
137:             */
138:            private Store store;
139:
140:            /**
141:             * The Evolver and catalog Data are non-null during catalog initialization,
142:             * and null otherwise.
143:             */
144:            private Evolver evolver;
145:            private Data catalogData;
146:
147:            /**
148:             * Creates a new catalog, opening the database and reading it from a given
149:             * catalog database if it already exists.  All predefined formats and
150:             * formats for the given model are added.  For modified classes, old
151:             * formats are defined based on the rules for compatible class changes and
152:             * the given mutations.  If any format is changed or added, and the
153:             * database is not read-only, write the initialized catalog to the
154:             * database.
155:             */
156:            public PersistCatalog(Transaction txn, Environment env,
157:                    String storePrefix, String dbName, DatabaseConfig dbConfig,
158:                    EntityModel modelParam, Mutations mutationsParam,
159:                    boolean rawAccess, Store store) throws DatabaseException {
160:
161:                this .rawAccess = rawAccess;
162:                this .store = store;
163:                db = env.openDatabase(txn, dbName, dbConfig);
164:                openCount = 1;
165:                boolean success = false;
166:                try {
167:                    catalogData = readData(txn);
168:                    mutations = catalogData.mutations;
169:                    if (mutations == null) {
170:                        mutations = new Mutations();
171:                    }
172:
173:                    /*
174:                     * When the beta version is detected, force a re-write of the
175:                     * catalog and disallow class changes.  This brings the catalog up
176:                     * to date so that evolution can proceed correctly from then on.
177:                     */
178:                    boolean betaVersion = (catalogData.version == BETA_VERSION);
179:                    boolean forceWriteData = betaVersion;
180:                    boolean disallowClassChanges = betaVersion;
181:
182:                    /*
183:                     * Store the given mutations if they are different from the stored
184:                     * mutations, and force evolution to apply the new mutations.
185:                     */
186:                    boolean forceEvolution = false;
187:                    if (mutationsParam != null
188:                            && !mutations.equals(mutationsParam)) {
189:                        mutations = mutationsParam;
190:                        forceWriteData = true;
191:                        forceEvolution = true;
192:                    }
193:
194:                    /* Get the existing format list, or copy it from SimpleCatalog. */
195:                    formatList = catalogData.formatList;
196:                    if (formatList == null) {
197:                        formatList = SimpleCatalog.copyFormatList();
198:
199:                        /*
200:                         * Special cases: Object and Number are predefined but are not
201:                         * simple types.
202:                         */
203:                        Format format = new NonPersistentFormat(Object.class);
204:                        format.setId(Format.ID_OBJECT);
205:                        formatList.set(Format.ID_OBJECT, format);
206:                        format = new NonPersistentFormat(Number.class);
207:                        format.setId(Format.ID_NUMBER);
208:                        formatList.set(Format.ID_NUMBER, format);
209:                    } else {
210:                        if (SimpleCatalog.copyMissingFormats(formatList)) {
211:                            forceWriteData = true;
212:                        }
213:                    }
214:
215:                    /* Special handling for JE 3.0.12 beta formats. */
216:                    if (betaVersion) {
217:                        Map<String, Format> formatMap = new HashMap<String, Format>();
218:                        for (Format format : formatList) {
219:                            if (format != null) {
220:                                formatMap.put(format.getClassName(), format);
221:                            }
222:                        }
223:                        for (Format format : formatList) {
224:                            if (format != null) {
225:                                format.migrateFromBeta(formatMap);
226:                            }
227:                        }
228:                    }
229:
230:                    /*
231:                     * If we should not use the current model, initialize the stored
232:                     * model and return.
233:                     */
234:                    formatMap = new HashMap<String, Format>(formatList.size());
235:                    latestFormatMap = new HashMap<String, Format>(formatList
236:                            .size());
237:                    if (rawAccess) {
238:                        for (Format format : formatList) {
239:                            if (format != null) {
240:                                String name = format.getClassName();
241:                                if (format.isCurrentVersion()) {
242:                                    formatMap.put(name, format);
243:                                }
244:                                if (format == format.getLatestVersion()) {
245:                                    latestFormatMap.put(name, format);
246:                                }
247:                            }
248:                        }
249:                        for (Format format : formatList) {
250:                            if (format != null) {
251:                                format.initializeIfNeeded(this );
252:                            }
253:                        }
254:                        model = new StoredModel(this );
255:                        success = true;
256:                        return;
257:                    }
258:
259:                    /*
260:                     * We are opening a store that uses the current model. Default to
261:                     * the AnnotationModel if no model is specified.
262:                     */
263:                    if (modelParam != null) {
264:                        model = modelParam;
265:                    } else {
266:                        model = new AnnotationModel();
267:                    }
268:
269:                    /*
270:                     * Add all predefined (simple) formats to the format map.  The
271:                     * current version of other formats will be added below.
272:                     */
273:                    for (int i = 0; i <= Format.ID_PREDEFINED; i += 1) {
274:                        Format simpleFormat = formatList.get(i);
275:                        if (simpleFormat != null) {
276:                            formatMap.put(simpleFormat.getClassName(),
277:                                    simpleFormat);
278:                        }
279:                    }
280:
281:                    /*
282:                     * Known classes are those explicitly registered by the user via
283:                     * the model, plus the predefined proxy classes.
284:                     */
285:                    List<String> knownClasses = new ArrayList<String>(model
286:                            .getKnownClasses());
287:                    addPredefinedProxies(knownClasses);
288:
289:                    /*
290:                     * Create a temporary map of proxied class name to proxy class
291:                     * name, using all known formats and classes.  This map is used to
292:                     * force proxy formats to be created prior to proxied formats.
293:                     * [#14665]
294:                     */
295:                    proxyClassMap = new HashMap<String, String>();
296:                    for (Format oldFormat : formatList) {
297:                        if (oldFormat == null || Format.isPredefined(oldFormat)) {
298:                            continue;
299:                        }
300:                        String oldName = oldFormat.getClassName();
301:                        Renamer renamer = mutations.getRenamer(oldName,
302:                                oldFormat.getVersion(), null);
303:                        String newName = (renamer != null) ? renamer
304:                                .getNewName() : oldName;
305:                        addProxiedClass(newName);
306:                    }
307:                    for (String className : knownClasses) {
308:                        addProxiedClass(className);
309:                    }
310:
311:                    /*
312:                     * Add known formats from the model and the predefined proxies.
313:                     * In general, classes will not be present in an AnnotationModel
314:                     * until an instance is stored, in which case an old format exists.
315:                     * However, registered proxy classes are an exception and must be
316:                     * added in advance.  And the user may choose to register new
317:                     * classes in advance.  The more formats we define in advance, the
318:                     * less times we have to write to the catalog database.
319:                     */
320:                    Map<String, Format> newFormats = new HashMap<String, Format>();
321:                    for (String className : knownClasses) {
322:                        createFormat(className, newFormats);
323:                    }
324:
325:                    /*
326:                     * Perform class evolution for all old formats, and throw an
327:                     * exception that contains the messages for all of the errors in
328:                     * mutations or in the definition of new classes.
329:                     */
330:                    evolver = new Evolver(this , storePrefix, mutations,
331:                            newFormats, forceEvolution, disallowClassChanges);
332:                    for (Format oldFormat : formatList) {
333:                        if (oldFormat == null || Format.isPredefined(oldFormat)) {
334:                            continue;
335:                        }
336:                        if (oldFormat.isEntity()) {
337:                            evolver.evolveFormat(oldFormat);
338:                        } else {
339:                            evolver.addNonEntityFormat(oldFormat);
340:                        }
341:                    }
342:                    evolver.finishEvolution();
343:                    String errors = evolver.getErrors();
344:                    if (errors != null) {
345:                        throw new IncompatibleClassException(errors);
346:                    }
347:
348:                    /*
349:                     * Add the new formats remaining.  New formats that are equal to
350:                     * old formats were removed from the newFormats map above.
351:                     */
352:                    for (Format newFormat : newFormats.values()) {
353:                        addFormat(newFormat);
354:                    }
355:
356:                    /* Initialize all formats. */
357:                    for (Format format : formatList) {
358:                        if (format != null) {
359:                            format.initializeIfNeeded(this );
360:                            if (format == format.getLatestVersion()) {
361:                                latestFormatMap.put(format.getClassName(),
362:                                        format);
363:                            }
364:                        }
365:                    }
366:
367:                    boolean needWrite = newFormats.size() > 0
368:                            || evolver.areFormatsChanged();
369:
370:                    /* For unit testing. */
371:                    if (expectNoClassChanges && needWrite) {
372:                        throw new IllegalStateException("Unexpected changes "
373:                                + " newFormats.size=" + newFormats.size()
374:                                + " areFormatsChanged="
375:                                + evolver.areFormatsChanged());
376:                    }
377:
378:                    /* Write the catalog if anything changed. */
379:                    if ((needWrite || forceWriteData)
380:                            && !db.getConfig().getReadOnly()) {
381:
382:                        /*
383:                         * Only rename/remove databases if we are going to update the
384:                         * catalog to reflect those class changes.
385:                         */
386:                        evolver.renameAndRemoveDatabases(env, txn);
387:
388:                        /*
389:                         * Note that we use the Data object that was read above, and
390:                         * the beta version determines whether to delete the old
391:                         * mutations record.
392:                         */
393:                        catalogData.formatList = formatList;
394:                        catalogData.mutations = mutations;
395:                        writeData(txn, catalogData);
396:                    } else if (forceWriteData) {
397:                        throw new IllegalArgumentException(
398:                                "When an upgrade is required the store may not be "
399:                                        + "opened read-only");
400:                    }
401:
402:                    success = true;
403:                } finally {
404:
405:                    /*
406:                     * Fields needed only for the duration of this ctor and which
407:                     * should be null afterwards.
408:                     */
409:                    proxyClassMap = null;
410:                    catalogData = null;
411:                    evolver = null;
412:
413:                    if (!success) {
414:                        close();
415:                    }
416:                }
417:            }
418:
419:            public void getEntityFormats(Collection<Format> entityFormats) {
420:                for (Format format : formatMap.values()) {
421:                    if (format.isEntity()) {
422:                        entityFormats.add(format);
423:                    }
424:                }
425:            }
426:
427:            private void addProxiedClass(String className) {
428:                ClassMetadata metadata = model.getClassMetadata(className);
429:                if (metadata != null) {
430:                    String proxiedClassName = metadata.getProxiedClassName();
431:                    if (proxiedClassName != null) {
432:                        proxyClassMap.put(proxiedClassName, className);
433:                    }
434:                }
435:            }
436:
437:            private void addPredefinedProxies(List<String> knownClasses) {
438:                knownClasses
439:                        .add(CollectionProxy.ArrayListProxy.class.getName());
440:                knownClasses.add(CollectionProxy.LinkedListProxy.class
441:                        .getName());
442:                knownClasses.add(CollectionProxy.HashSetProxy.class.getName());
443:                knownClasses.add(CollectionProxy.TreeSetProxy.class.getName());
444:                knownClasses.add(MapProxy.HashMapProxy.class.getName());
445:                knownClasses.add(MapProxy.TreeMapProxy.class.getName());
446:            }
447:
448:            /**
449:             * Returns a map from format to a set of its superclass formats.  The
450:             * format for simple types, enums and class Object are not included.  Only
451:             * complex types have superclass formats as defined by
452:             * Format.getSuperFormat.
453:             */
454:            Map<Format, Set<Format>> getSubclassMap() {
455:                Map<Format, Set<Format>> subclassMap = new HashMap<Format, Set<Format>>();
456:                for (Format format : formatList) {
457:                    if (format == null || Format.isPredefined(format)) {
458:                        continue;
459:                    }
460:                    Format super Format = format.getSuperFormat();
461:                    if (super Format != null) {
462:                        Set<Format> subclass = subclassMap.get(super Format);
463:                        if (subclass == null) {
464:                            subclass = new HashSet<Format>();
465:                            subclassMap.put(super Format, subclass);
466:                        }
467:                        subclass.add(format);
468:                    }
469:                }
470:                return subclassMap;
471:            }
472:
473:            /**
474:             * Returns the model parameter, default model or stored model.
475:             */
476:            public EntityModel getResolvedModel() {
477:                return model;
478:            }
479:
480:            /**
481:             * Increments the reference count for a catalog that is already open.
482:             */
483:            public void openExisting() {
484:                openCount += 1;
485:            }
486:
487:            /**
488:             * Decrements the reference count and closes the catalog DB when it reaches
489:             * zero.  Returns true if the database was closed or false if the reference
490:             * count is still non-zero and the database was left open.
491:             */
492:            public boolean close() throws DatabaseException {
493:
494:                if (openCount == 0) {
495:                    throw new IllegalStateException("Catalog is not open");
496:                } else {
497:                    openCount -= 1;
498:                    if (openCount == 0) {
499:                        Database dbToClose = db;
500:                        db = null;
501:                        dbToClose.close();
502:                        return true;
503:                    } else {
504:                        return false;
505:                    }
506:                }
507:            }
508:
509:            /**
510:             * Returns the current merged mutations.
511:             */
512:            public Mutations getMutations() {
513:                return mutations;
514:            }
515:
516:            /**
517:             * Convenience method that gets the class for the given class name and
518:             * calls createFormat with the class object.
519:             */
520:            public Format createFormat(String clsName,
521:                    Map<String, Format> newFormats) {
522:                Class type;
523:                try {
524:                    type = SimpleCatalog.classForName(clsName);
525:                } catch (ClassNotFoundException e) {
526:                    throw new IllegalStateException("Class does not exist: "
527:                            + clsName);
528:                }
529:                return createFormat(type, newFormats);
530:            }
531:
532:            /**
533:             * If the given class format is not already present in the given map,
534:             * creates an uninitialized format, adds it to the map, and also collects
535:             * related formats in the map.
536:             */
537:            public Format createFormat(Class type,
538:                    Map<String, Format> newFormats) {
539:                /* Return a new or existing format for this class. */
540:                String className = type.getName();
541:                Format format = newFormats.get(className);
542:                if (format != null) {
543:                    return format;
544:                }
545:                format = formatMap.get(className);
546:                if (format != null) {
547:                    return format;
548:                }
549:                /* Simple types are predefined. */
550:                assert !SimpleCatalog.isSimpleType(type) : className;
551:                /* Create format of the appropriate type. */
552:                String proxyClassName = null;
553:                if (proxyClassMap != null) {
554:                    proxyClassName = proxyClassMap.get(className);
555:                }
556:                if (proxyClassName != null) {
557:                    format = new ProxiedFormat(type, proxyClassName);
558:                } else if (type.isArray()) {
559:                    format = type.getComponentType().isPrimitive() ? (new PrimitiveArrayFormat(
560:                            type))
561:                            : (new ObjectArrayFormat(type));
562:                } else if (type.isEnum()) {
563:                    format = new EnumFormat(type);
564:                } else if (type == Object.class || type.isInterface()) {
565:                    format = new NonPersistentFormat(type);
566:                } else {
567:                    ClassMetadata metadata = model.getClassMetadata(className);
568:                    if (metadata == null) {
569:                        throw new IllegalArgumentException(
570:                                "Class could not be loaded or is not persistent: "
571:                                        + className);
572:                    }
573:                    if (metadata.getCompositeKeyFields() != null
574:                            && (metadata.getPrimaryKey() != null || metadata
575:                                    .getSecondaryKeys() != null)) {
576:                        throw new IllegalArgumentException(
577:                                "A composite key class may not have primary or"
578:                                        + " secondary key fields: "
579:                                        + type.getName());
580:                    }
581:                    try {
582:                        type.getDeclaredConstructor();
583:                    } catch (NoSuchMethodException e) {
584:                        throw new IllegalArgumentException(
585:                                "No default constructor: " + type.getName(), e);
586:                    }
587:                    if (metadata.getCompositeKeyFields() != null) {
588:                        format = new CompositeKeyFormat(type, metadata,
589:                                metadata.getCompositeKeyFields());
590:                    } else {
591:                        EntityMetadata entityMetadata = model
592:                                .getEntityMetadata(className);
593:                        format = new ComplexFormat(type, metadata,
594:                                entityMetadata);
595:                    }
596:                }
597:                /* Collect new format along with any related new formats. */
598:                newFormats.put(className, format);
599:                format.collectRelatedFormats(this , newFormats);
600:
601:                return format;
602:            }
603:
604:            /**
605:             * Adds a format and makes it the current format for the class.
606:             */
607:            private void addFormat(Format format) {
608:                addFormat(format, formatList, formatMap);
609:            }
610:
611:            /**
612:             * Adds a format to the given the format collections, for use when
613:             * dynamically adding formats.
614:             */
615:            private void addFormat(Format format, List<Format> list,
616:                    Map<String, Format> map) {
617:                format.setId(list.size());
618:                list.add(format);
619:                map.put(format.getClassName(), format);
620:            }
621:
622:            /**
623:             * Installs an existing format when no evolution is needed, i.e, when the
624:             * new and old formats are identical.
625:             */
626:            void useExistingFormat(Format oldFormat) {
627:                assert oldFormat.isCurrentVersion();
628:                formatMap.put(oldFormat.getClassName(), oldFormat);
629:            }
630:
631:            /**
632:             * Returns a set of all persistent (non-simple type) class names.
633:             */
634:            Set<String> getModelClasses() {
635:                Set<String> classes = new HashSet<String>();
636:                for (Format format : formatMap.values()) {
637:                    if (format.isModelClass()) {
638:                        classes.add(format.getClassName());
639:                    }
640:                }
641:                return classes;
642:            }
643:
644:            /**
645:             * When a format is intialized, this method is called to get the version
646:             * of the serialized object to be initialized.  See Catalog.
647:             */
648:            public int getInitVersion(Format format, boolean forReader) {
649:
650:                if (catalogData == null || catalogData.formatList == null
651:                        || format.getId() >= catalogData.formatList.size()) {
652:
653:                    /*
654:                     * For new formats, use the current version.  If catalogData is
655:                     * null, the Catalog ctor is finished and the format must be new.
656:                     * If the ctor is in progress, the format is new if its ID is
657:                     * greater than the ID of all pre-existing formats.
658:                     */
659:                    return Catalog.CURRENT_VERSION;
660:                } else {
661:
662:                    /*
663:                     * Get the version of a pre-existing format during execution of the
664:                     * Catalog ctor.  The catalogData field is non-null, but evolver
665:                     * may be null if the catalog is opened in raw mode.
666:                     */
667:                    assert catalogData != null;
668:
669:                    if (forReader) {
670:
671:                        /*
672:                         * Get the version of the evolution reader for a pre-existing
673:                         * format.  Use the current version if the format changed
674:                         * during class evolution, otherwise use the stored version.
675:                         */
676:                        return (evolver != null && evolver
677:                                .isFormatChanged(format)) ? Catalog.CURRENT_VERSION
678:                                : catalogData.version;
679:                    } else {
680:                        /* Always used the stored version for a pre-existing format. */
681:                        return catalogData.version;
682:                    }
683:                }
684:            }
685:
686:            public Format getFormat(int formatId) {
687:                try {
688:                    Format format = formatList.get(formatId);
689:                    if (format == null) {
690:                        throw new DeletedClassException(
691:                                "Format does not exist: " + formatId);
692:                    }
693:                    return format;
694:                } catch (NoSuchElementException e) {
695:                    throw new DeletedClassException("Format does not exist: "
696:                            + formatId);
697:                }
698:            }
699:
700:            /**
701:             * Get a format for a given class, creating it if it does not exist.
702:             *
703:             * <p>This method is called for top level entity instances by
704:             * PersistEntityBinding.  When a new entity subclass format is added we
705:             * call Store.openSecondaryIndexes so that previously unknown secondary
706:             * databases can be created, before storing the entity.  We do this here
707:             * while not holding a synchronization mutex, not in addNewFormat, to avoid
708:             * deadlocks. openSecondaryIndexes synchronizes on the Store. [#15247]</p>
709:             */
710:            public Format getFormat(Class cls) {
711:                Format format = formatMap.get(cls.getName());
712:                if (format == null) {
713:                    if (model != null) {
714:                        format = addNewFormat(cls);
715:                        /* Detect and handle new entity subclass. [#15247] */
716:                        if (store != null) {
717:                            Format entityFormat = format.getEntityFormat();
718:                            if (entityFormat != null && entityFormat != format) {
719:                                try {
720:                                    store.openSecondaryIndexes(null,
721:                                            entityFormat.getEntityMetadata(),
722:                                            null);
723:                                } catch (DatabaseException e) {
724:                                    throw new RuntimeExceptionWrapper(e);
725:                                }
726:                            }
727:                        }
728:                    }
729:                    if (format == null) {
730:                        throw new IllegalArgumentException(
731:                                "Class is not persistent: " + cls.getName());
732:                    }
733:                }
734:                return format;
735:            }
736:
737:            public Format getFormat(String className) {
738:                return formatMap.get(className);
739:            }
740:
741:            public Format getLatestVersion(String className) {
742:                return latestFormatMap.get(className);
743:            }
744:
745:            /**
746:             * Adds a format for a new class.  Returns the format added for the given
747:             * class, or throws an exception if the given class is not persistent.
748:             *
749:             * <p>This method uses a copy-on-write technique to add new formats without
750:             * impacting other threads.</p>
751:             */
752:            private synchronized Format addNewFormat(Class cls) {
753:
754:                /*
755:                 * After synchronizing, check whether another thread has added the
756:                 * format needed.  Note that this is not the double-check technique
757:                 * because the formatMap field is volatile and is not itself checked
758:                 * for null.  (The double-check technique is known to be flawed in
759:                 * Java.)
760:                 */
761:                Format format = formatMap.get(cls.getName());
762:                if (format != null) {
763:                    return format;
764:                }
765:
766:                /* Copy the read-only format collections. */
767:                List<Format> newFormatList = new ArrayList<Format>(formatList);
768:                Map<String, Format> newFormatMap = new HashMap<String, Format>(
769:                        formatMap);
770:                Map<String, Format> newLatestFormatMap = new HashMap<String, Format>(
771:                        latestFormatMap);
772:
773:                /* Add the new format and all related new formats. */
774:                Map<String, Format> newFormats = new HashMap<String, Format>();
775:                format = createFormat(cls, newFormats);
776:                for (Format newFormat : newFormats.values()) {
777:                    addFormat(newFormat, newFormatList, newFormatMap);
778:                }
779:
780:                /*
781:                 * Initialize new formats using a read-only catalog because we can't
782:                 * update this catalog until after we store it (below).
783:                 */
784:                Catalog newFormatCatalog = new ReadOnlyCatalog(newFormatList,
785:                        newFormatMap);
786:                for (Format newFormat : newFormats.values()) {
787:                    newFormat.initializeIfNeeded(newFormatCatalog);
788:                    newLatestFormatMap.put(newFormat.getClassName(), newFormat);
789:                }
790:
791:                /*
792:                 * Write the updated catalog using auto-commit, then assign the new
793:                 * collections.  The database write must occur before the collections
794:                 * are used, since a format must be persistent before it can be
795:                 * referenced by a data record.
796:                 */
797:                try {
798:                    Data catalogData = new Data();
799:                    catalogData.formatList = newFormatList;
800:                    catalogData.mutations = mutations;
801:                    writeData(null, catalogData);
802:                } catch (DatabaseException e) {
803:                    throw new RuntimeExceptionWrapper(e);
804:                }
805:                formatList = newFormatList;
806:                formatMap = newFormatMap;
807:                latestFormatMap = newLatestFormatMap;
808:
809:                return format;
810:            }
811:
812:            /**
813:             * Used to write the catalog when a format has been changed, for example,
814:             * when Store.evolve has updated a Format's EvolveNeeded property.  Uses
815:             * auto-commit.
816:             */
817:            public synchronized void flush() throws DatabaseException {
818:
819:                Data catalogData = new Data();
820:                catalogData.formatList = formatList;
821:                catalogData.mutations = mutations;
822:                writeData(null, catalogData);
823:            }
824:
825:            /**
826:             * Reads catalog Data, converting old versions as necessary.  An empty
827:             * Data object is returned if no catalog data currently exists.  Null is
828:             * never returned.
829:             */
830:            private Data readData(Transaction txn) throws DatabaseException {
831:
832:                Data catalogData;
833:                DatabaseEntry key = new DatabaseEntry(DATA_KEY);
834:                DatabaseEntry data = new DatabaseEntry();
835:                OperationStatus status = db.get(txn, key, data, null);
836:                if (status == OperationStatus.SUCCESS) {
837:                    ByteArrayInputStream bais = new ByteArrayInputStream(data
838:                            .getData(), data.getOffset(), data.getSize());
839:                    try {
840:                        ObjectInputStream ois = new ObjectInputStream(bais);
841:                        Object object = ois.readObject();
842:                        assert ois.available() == 0;
843:                        if (object instanceof  Data) {
844:                            catalogData = (Data) object;
845:                        } else {
846:                            if (!(object instanceof  List)) {
847:                                throw new IllegalStateException(object
848:                                        .getClass().getName());
849:                            }
850:                            catalogData = new Data();
851:                            catalogData.formatList = (List) object;
852:                            catalogData.version = BETA_VERSION;
853:                        }
854:                        return catalogData;
855:                    } catch (ClassNotFoundException e) {
856:                        throw new DatabaseException(e);
857:                    } catch (IOException e) {
858:                        throw new DatabaseException(e);
859:                    }
860:                } else {
861:                    catalogData = new Data();
862:                    catalogData.version = Catalog.CURRENT_VERSION;
863:                }
864:                return catalogData;
865:            }
866:
867:            /**
868:             * Writes catalog Data.  If txn is null, auto-commit is used.
869:             */
870:            private void writeData(Transaction txn, Data catalogData)
871:                    throws DatabaseException {
872:
873:                /* Catalog data is written in the current version. */
874:                boolean wasBetaVersion = (catalogData.version == BETA_VERSION);
875:                catalogData.version = CURRENT_VERSION;
876:
877:                ByteArrayOutputStream baos = new ByteArrayOutputStream();
878:                try {
879:                    ObjectOutputStream oos = new ObjectOutputStream(baos);
880:                    oos.writeObject(catalogData);
881:                } catch (IOException e) {
882:                    throw new DatabaseException(e);
883:                }
884:                DatabaseEntry key = new DatabaseEntry(DATA_KEY);
885:                DatabaseEntry data = new DatabaseEntry(baos.toByteArray());
886:                db.put(txn, key, data);
887:
888:                /*
889:                 * Delete the unused beta mutations record if we read the beta version
890:                 * record earlier.
891:                 */
892:                if (wasBetaVersion) {
893:                    key.setData(BETA_MUTATIONS_KEY);
894:                    db.delete(txn, key);
895:                }
896:            }
897:
898:            public boolean isRawAccess() {
899:                return rawAccess;
900:            }
901:
902:            public Object convertRawObject(RawObject o,
903:                    IdentityHashMap converted) {
904:                Format format = (Format) o.getType();
905:                if (this  != format.getCatalog()) {
906:                    String className = format.getClassName();
907:                    format = getFormat(className);
908:                    if (format == null) {
909:                        throw new IllegalArgumentException(
910:                                "External raw type not found: " + className);
911:                    }
912:                }
913:                Format proxiedFormat = format.getProxiedFormat();
914:                if (proxiedFormat != null) {
915:                    format = proxiedFormat;
916:                }
917:                if (converted == null) {
918:                    converted = new IdentityHashMap();
919:                }
920:                return format.convertRawObject(this , false, o, converted);
921:            }
922:
923:            public void dump() {
924:                System.out.println("--- Begin formats ---");
925:                for (Format format : formatList) {
926:                    if (format != null) {
927:                        System.out.println("ID: "
928:                                + format.getId()
929:                                + " class: "
930:                                + format.getClassName()
931:                                + " version: "
932:                                + format.getVersion()
933:                                + " current: "
934:                                + (format == formatMap.get(format
935:                                        .getClassName())));
936:                    }
937:                }
938:                System.out.println("--- End formats ---");
939:            }
940:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.