• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/db-4.8.30/java/src/com/sleepycat/persist/impl/
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9package com.sleepycat.persist.impl;
10
11import java.io.Serializable;
12import java.util.HashSet;
13import java.util.IdentityHashMap;
14import java.util.List;
15import java.util.Map;
16import java.util.Set;
17
18import com.sleepycat.persist.evolve.Converter;
19import com.sleepycat.persist.model.ClassMetadata;
20import com.sleepycat.persist.model.EntityMetadata;
21import com.sleepycat.persist.model.EntityModel;
22import com.sleepycat.persist.model.FieldMetadata;
23import com.sleepycat.persist.model.PrimaryKeyMetadata;
24import com.sleepycat.persist.model.SecondaryKeyMetadata;
25import com.sleepycat.persist.raw.RawField;
26import com.sleepycat.persist.raw.RawObject;
27import com.sleepycat.persist.raw.RawType;
28
29/**
30 * The base class for all object formats.  Formats are used to define the
31 * stored layout for all persistent classes, including simple types.
32 *
33 * The design documentation below describes the storage format for entities and
34 * its relationship to information stored per format in the catalog.
35 *
36 * Requirements
37 * ------------
38 * + Provides EntityBinding for objects and EntryBinding for keys.
39 * + Provides SecondaryKeyCreator, SecondaryMultiKeyCreator and
40 *   SecondaryMultiKeyNullifier (SecondaryKeyNullifier is redundant).
41 * + Works with reflection and bytecode enhancement.
42 * + For reflection only, works with any entity model not just annotations.
43 * + Bindings are usable independently of the persist API.
44 * + Performance is almost equivalent to hand coded tuple bindings.
45 * + Small performance penalty for compatible class changes (new fields,
46 *   widening).
47 * + Secondary key create/nullify do not have to deserialize the entire record;
48 *   in other words, store secondary keys at the start of the data.
49 *
50 * Class Format
51 * ------------
52 * Every distinct class format is given a unique format ID.  Class IDs are not
53 * equivalent to class version numbers (as in the version property of @Entity
54 * and @Persistent) because the format can change when the version number does
55 * not.  Changes that cause a unique format ID to be assigned are:
56 *
57 * + Add field.
58 * + Widen field type.
59 * + Change primitive type to primitive wrapper class.
60 * + Add or drop secondary key.
61 * + Any incompatible class change.
62 *
63 * The last item, incompatible class changes, also correspond to a class
64 * version change.
65 *
66 * For each distinct class format the following information is conceptually
67 * stored in the catalog, keyed by format ID.
68 *
69 * - Class name
70 * - Class version number
71 * - Superclass format
72 * - Kind: simple, enum, complex, array
73 * - For kind == simple:
74 *     - Primitive class
75 * - For kind == enum:
76 *     - Array of constant names, sorted by name.
77 * - For kind == complex:
78 *     - Primary key fieldInfo, or null if no primary key is declared
79 *     - Array of secondary key fieldInfo, sorted by field name
80 *     - Array of other fieldInfo, sorted by field name
81 * - For kind == array:
82 *     - Component class format
83 *     - Number of array dimensions
84 * - Other metadata for RawType
85 *
86 * Where fieldInfo is:
87 *     - Field name
88 *     - Field class
89 *     - Other metadata for RawField
90 *
91 * Data Layout
92 * -----------
93 * For each entity instance the data layout is as follows:
94 *
95 *   instanceData: formatId keyFields... nonKeyFields...
96 *   keyFields:    fieldValue...
97 *   nonKeyFields: fieldValue...
98 *
99 * The formatId is the (positive non-zero) ID of a class format, defined above.
100 * This is ID of the most derived class of the instance.  It is stored as a
101 * packed integer.
102 *
103 * Following the format ID, zero or more sets of secondary key field values
104 * appear, followed by zero or more sets of other class field values.
105 *
106 * The keyFields are the sets of secondary key fields for each class in order
107 * of the highest superclass first.  Within a class, fields are ordered by
108 * field name.
109 *
110 * The nonKeyFields are the sets of other non-key fields for each class in
111 * order of the highest superclass first.  Within a class, fields are ordered
112 * by field name.
113 *
114 * A field value is:
115 *
116 *   fieldValue:   primitiveValue
117 *               | nullId
118 *               | instanceRef
119 *               | instanceData
120 *               | simpleValue
121 *               | enumValue
122 *               | arrayValue
123 *
124 * For a primitive type, a primitive value is used as defined for tuple
125 * bindings.  For float and double, sorted float and sorted double tuple values
126 * are used.
127 *
128 * For a non-primitive type with a null value, a nullId is used that has a zero
129 * (illegal formatId) value.  This includes String and other simple reference
130 * types.  The formatId is stored as a packed integer, meaning that it is
131 * stored as a single zero byte.
132 *
133 * For a non-primitive type, an instanceRef is used for a non-null instance
134 * that appears earlier in the data byte array.  An instanceRef is the negation
135 * of the byte offset of the instanceData that appears earlier.  It is stored
136 * as a packed integer.
137 *
138 * The remaining rules apply only to reference types with non-null values that
139 * do not appear earlier in the data array.
140 *
141 * For an array type, an array formatId is used that identifies the component
142 * type and the number of array dimensions.  This is followed by an array
143 * length (stored as a packed integer) and zero or more fieldValue elements.
144 * For an array with N+1 dimensions where N is greater than zero, the leftmost
145 * dimension is enumerated such that each fieldValue element is itself an array
146 * of N dimensions or null.
147 *
148 *   arrayValue:  formatId length fieldValue...
149 *
150 * For an enum type, an enumValue is used, consisting of a formatId that
151 * identifies the enum class and an enumIndex (stored as a packed integer) that
152 * identifies the constant name in the enum constant array of the enum class
153 * format:
154 *
155 *   enumValue:   formatId enumIndex
156 *
157 * For a simple type, a simpleValue is used.  This consists of the formatId
158 * that identifies the class followed by the simple type value.  For a
159 * primitive wrapper type the simple type value is the corresponding primitive,
160 * for a Date it is the milliseconds as a long primitive, and for BigInteger or
161 * BigDecimal it is a byte array as defined for tuple bindings of these types.
162 *
163 *   simpleValue: formatId value
164 *
165 * For all other complex types, an instanceData is used, which is defined
166 * above.
167 *
168 * Secondary Keys
169 * --------------
170 * For secondary key support we must account for writing and nullifying
171 * specific keys.  Rather than instantiating the entity and then performing
172 * the secondary key operation, we strive to perform the secondary key
173 * operation directly on the byte format.
174 *
175 * To create a secondary key we skip over other fields and then copy the bytes
176 * of the embedded key.  This approach is very efficient because a) the entity
177 * is not instantiated, and b) the secondary keys are stored at the beginning
178 * of the byte format and can be quickly read.
179 *
180 * To nullify we currently instantiate the raw entity, set the key field to null
181 * (or remove it from the array/collection), and convert the raw entity back to
182 * bytes.  Although the performance of this approach is not ideal because it
183 * requires serialization, it avoids the complexity of modifying the packed
184 * serialized format directly, adjusting references to key objects, etc.  Plus,
185 * when we nullify a key we are going to write the record, so the serialization
186 * overhead may not be significant.  For the record, I tried implementing
187 * nullification of the bytes directly and found it was much too complex.
188 *
189 * Lifecycle
190 * ---------
191 * Format are managed by a Catalog class.  Simple formats are managed by
192 * SimpleCatalog, and are copied from the SimpleCatalog by PersistCatalog.
193 * Other formats are managed by PersistCatalog.  The lifecycle of a format
194 * instance is:
195 *
196 * - Constructed by the catalog when a format is requested for a Class
197 *   that currently has no associated format.
198 *
199 * - The catalog calls setId() and adds the format to its format list
200 *   (indexed by format id) and map (keyed by class name).
201 *
202 * - The catalog calls collectRelatedFormats(), where a format can create
203 *   additional formats that it needs, or that should also be persistent.
204 *
205 * - The catalog calls initializeIfNeeded(), which calls the initialize()
206 *   method of the format class.
207 *
208 * - initialize() should initialize any transient fields in the format.
209 *   initialize() can assume that all related formats are available in the
210 *   catalog.  It may call initializeIfNeeded() for those related formats, if
211 *   it needs to interact with an initialized related format; this does not
212 *   cause a cycle, because initializeIfNeeded() does nothing for an already
213 *   initialized format.
214 *
215 * - The catalog creates a group of related formats at one time, and then
216 *   writes its entire list of formats to the catalog DB as a single record.
217 *   This grouping reduces the number of writes.
218 *
219 * - When a catalog is opened and the list of existing formats is read.  After
220 *   a format is deserialized, its initializeIfNeeded() method is called.
221 *   setId() and collectRelatedFormats() are not called, since the ID and
222 *   related formats are stored in serialized fields.
223 *
224 * - There are two modes for opening an existing catalog: raw mode and normal
225 *   mode.  In raw mode, the old format is used regardless of whether it
226 *   matches the current class definition; in fact the class is not accessed
227 *   and does not need to be present.
228 *
229 * - In normal mode, for each existing format that is initialized, a new format
230 *   is also created based on the current class and metadata definition.  If
231 *   the two formats are equal, the new format is discarded.  If they are
232 *   unequal, the new format becomes the current format and the old format's
233 *   evolve() method is called.  evolve() is responsible for adjusting the
234 *   old format for class evolution.  Any number of non-current formats may
235 *   exist for a given class, and are setup to evolve the single current format
236 *   for the class.
237 *
238 * @author Mark Hayes
239 */
240public abstract class Format implements Reader, RawType, Serializable {
241
242    private static final long serialVersionUID = 545633644568489850L;
243
244    /** Null reference. */
245    static final int ID_NULL     = 0;
246    /** Object */
247    static final int ID_OBJECT   = 1;
248    /** Boolean */
249    static final int ID_BOOL     = 2;
250    static final int ID_BOOL_W   = 3;
251    /** Byte */
252    static final int ID_BYTE     = 4;
253    static final int ID_BYTE_W   = 5;
254    /** Short */
255    static final int ID_SHORT    = 6;
256    static final int ID_SHORT_W  = 7;
257    /** Integer */
258    static final int ID_INT      = 8;
259    static final int ID_INT_W    = 9;
260    /** Long */
261    static final int ID_LONG     = 10;
262    static final int ID_LONG_W   = 11;
263    /** Float */
264    static final int ID_FLOAT    = 12;
265    static final int ID_FLOAT_W  = 13;
266    /** Double */
267    static final int ID_DOUBLE   = 14;
268    static final int ID_DOUBLE_W = 15;
269    /** Character */
270    static final int ID_CHAR     = 16;
271    static final int ID_CHAR_W   = 17;
272    /** String */
273    static final int ID_STRING   = 18;
274    /** BigInteger */
275    static final int ID_BIGINT   = 19;
276    /** BigDecimal */
277    static final int ID_BIGDEC   = 20;
278    /** Date */
279    static final int ID_DATE     = 21;
280    /** Number */
281    static final int ID_NUMBER   = 22;
282
283    /** First simple type. */
284    static final int ID_SIMPLE_MIN  = 2;
285    /** Last simple type. */
286    static final int ID_SIMPLE_MAX  = 21;
287    /** Last predefined ID, after which dynamic IDs are assigned. */
288    static final int ID_PREDEFINED  = 30;
289
290    static boolean isPredefined(Format format) {
291        return format.getId() <= ID_PREDEFINED;
292    }
293
294    private int id;
295    private String className;
296    private Reader reader;
297    private Format superFormat;
298    private Format latestFormat;
299    private Format previousFormat;
300    private Set<String> supertypes;
301    private boolean deleted;
302    private boolean unused;
303    private transient Catalog catalog;
304    private transient Class type;
305    private transient Format proxiedFormat;
306    private transient boolean initialized;
307
308    /**
309     * Creates a new format for a given class.
310     */
311    Format(Class type) {
312        this(type.getName());
313        this.type = type;
314        addSupertypes();
315    }
316
317    /**
318     * Creates a format for class evolution when no class may be present.
319     */
320    Format(String className) {
321        this.className = className;
322        latestFormat = this;
323        supertypes = new HashSet<String>();
324    }
325
326    /**
327     * Special handling for JE 3.0.12 beta formats.
328     */
329    void migrateFromBeta(Map<String,Format> formatMap) {
330        if (latestFormat == null) {
331            latestFormat = this;
332        }
333    }
334
335    final boolean isNew() {
336        return id == 0;
337    }
338
339    final Catalog getCatalog() {
340        return catalog;
341    }
342
343    /**
344     * Returns the format ID.
345     */
346    public final int getId() {
347        return id;
348    }
349
350    /**
351     * Called by the Catalog to set the format ID when a new format is added to
352     * the format list, before calling initializeIfNeeded().
353     */
354    final void setId(int id) {
355        this.id = id;
356    }
357
358    /**
359     * Returns the class that this format represents.  This method will return
360     * null in rawAccess mode, or for an unevolved format.
361     */
362    final Class getType() {
363        return type;
364    }
365
366    /**
367     * Called to get the type when it is known to exist for an uninitialized
368     * format.
369     */
370    final Class getExistingType() {
371        if (type == null) {
372            try {
373                type = SimpleCatalog.classForName(className);
374            } catch (ClassNotFoundException e) {
375                throw new IllegalStateException(e);
376            }
377        }
378        return type;
379    }
380
381    /**
382     * Returns the object for reading objects of the latest format.  For the
383     * latest version format, 'this' is returned.  For prior version formats, a
384     * reader that converts this version to the latest version is returned.
385     */
386    final Reader getReader() {
387
388        /*
389         * For unit testing, record whether any un-evolved formats are
390         * encountered.
391         */
392        if (this != reader) {
393            PersistCatalog.unevolvedFormatsEncountered = true;
394        }
395
396        return reader;
397    }
398
399    /**
400     * Changes the reader during format evolution.
401     */
402    final void setReader(Reader reader) {
403        this.reader = reader;
404    }
405
406    /**
407     * Returns the format of the superclass.
408     */
409    final Format getSuperFormat() {
410        return superFormat;
411    }
412
413    /**
414     * Called to set the format of the superclass during initialize().
415     */
416    final void setSuperFormat(Format superFormat) {
417        this.superFormat = superFormat;
418    }
419
420    /**
421     * Returns the format that is proxied by this format.  If non-null is
422     * returned, then this format is a PersistentProxy.
423     */
424    final Format getProxiedFormat() {
425        return proxiedFormat;
426    }
427
428    /**
429     * Called by ProxiedFormat to set the proxied format.
430     */
431    final void setProxiedFormat(Format proxiedFormat) {
432        this.proxiedFormat = proxiedFormat;
433    }
434
435    /**
436     * If this is the latest/evolved format, returns this; otherwise, returns
437     * the current version of this format.  Note that this WILL return a
438     * format for a deleted class if the latest format happens to be deleted.
439     */
440    final Format getLatestVersion() {
441        return latestFormat;
442    }
443
444    /**
445     * Returns the previous version of this format in the linked list of
446     * versions, or null if this is the only version.
447     */
448    public final Format getPreviousVersion() {
449        return previousFormat;
450    }
451
452    /**
453     * Called by Evolver to set the latest format when this old format is
454     * evolved.
455     */
456    final void setLatestVersion(Format newFormat) {
457
458        /*
459         * If this old format is the former latest version, link it to the new
460         * latest version.  This creates a singly linked list of versions
461         * starting with the latest.
462         */
463        if (latestFormat == this) {
464            newFormat.previousFormat = this;
465        }
466
467        latestFormat = newFormat;
468    }
469
470    /**
471     * Returns whether the class for this format was deleted.
472     */
473    final boolean isDeleted() {
474        return deleted;
475    }
476
477    /**
478     * Called by the Evolver when applying a Deleter mutation.
479     */
480    final void setDeleted(boolean deleted) {
481        this.deleted = deleted;
482    }
483
484    /**
485     * Called by the Evolver for a format that is never referenced.
486     */
487    final void setUnused(boolean unused) {
488        this.unused = unused;
489    }
490
491    /**
492     * Called by the Evolver with true when an entity format or any of its
493     * nested format were changed.  Called by Store.evolve when an entity has
494     * been fully converted.  Overridden by ComplexFormat.
495     */
496    void setEvolveNeeded(boolean needed) {
497        throw new UnsupportedOperationException();
498    }
499
500    /**
501     * Overridden by ComplexFormat.
502     */
503    boolean getEvolveNeeded() {
504        throw new UnsupportedOperationException();
505    }
506
507    final boolean isInitialized() {
508        return initialized;
509    }
510
511    /**
512     * Called by the Catalog to initialize a format, and may also be called
513     * during initialize() for a related format to ensure that the related
514     * format is initialized.  This latter case is allowed to support
515     * bidirectional dependencies.  This method will do nothing if the format
516     * is already intialized.
517     */
518    final void initializeIfNeeded(Catalog catalog, EntityModel model) {
519        if (!initialized) {
520            initialized = true;
521            this.catalog = catalog;
522
523            /* Initialize objects serialized by an older Format class. */
524            if (latestFormat == null) {
525                latestFormat = this;
526            }
527            if (reader == null) {
528                reader = this;
529            }
530
531            /*
532             * The class is only guaranteed to be available in live (not raw)
533             * mode, for the current version of the format.
534             */
535            if (type == null &&
536                isCurrentVersion() &&
537                (isSimple() || !catalog.isRawAccess())) {
538                getExistingType();
539            }
540
541            /* Perform subclass-specific initialization. */
542            initialize(catalog, model,
543                       catalog.getInitVersion(this, false /*forReader*/));
544            reader.initializeReader
545                (catalog, model,
546                 catalog.getInitVersion(this, true /*forReader*/),
547                 this);
548        }
549    }
550
551    /**
552     * Called to initialize a separate Reader implementation.  This method is
553     * called when no separate Reader exists, and does nothing.
554     */
555    public void initializeReader(Catalog catalog,
556                                 EntityModel model,
557                                 int initVersion,
558                                 Format oldFormat) {
559    }
560
561    /**
562     * Adds all interfaces and superclasses to the supertypes set.
563     */
564    private void addSupertypes() {
565        addInterfaces(type);
566        Class stype = type.getSuperclass();
567        while (stype != null && stype != Object.class) {
568            supertypes.add(stype.getName());
569            addInterfaces(stype);
570            stype = stype.getSuperclass();
571        }
572    }
573
574    /**
575     * Recursively adds interfaces to the supertypes set.
576     */
577    private void addInterfaces(Class cls) {
578        Class[] interfaces = cls.getInterfaces();
579        for (Class iface : interfaces) {
580            if (iface != Enhanced.class) {
581                supertypes.add(iface.getName());
582                addInterfaces(iface);
583            }
584        }
585    }
586
587    /**
588     * Certain formats (ProxiedFormat for example) prohibit nested fields that
589     * reference the parent object. [#15815]
590     */
591    boolean areNestedRefsProhibited() {
592        return false;
593    }
594
595    /* -- Start of RawType interface methods. -- */
596
597    public String getClassName() {
598        return className;
599    }
600
601    public int getVersion() {
602        ClassMetadata meta = getClassMetadata();
603        if (meta != null) {
604            return meta.getVersion();
605        } else {
606            return 0;
607        }
608    }
609
610    public Format getSuperType() {
611        return superFormat;
612    }
613
614    /* -- RawType methods that are overridden as needed in subclasses. -- */
615
616    public boolean isSimple() {
617        return false;
618    }
619
620    public boolean isPrimitive() {
621        return false;
622    }
623
624    public boolean isEnum() {
625        return false;
626    }
627
628    public List<String> getEnumConstants() {
629        return null;
630    }
631
632    public boolean isArray() {
633        return false;
634    }
635
636    public int getDimensions() {
637        return 0;
638    }
639
640    public Format getComponentType() {
641        return null;
642    }
643
644    public Map<String,RawField> getFields() {
645        return null;
646    }
647
648    public ClassMetadata getClassMetadata() {
649        return null;
650    }
651
652    public EntityMetadata getEntityMetadata() {
653        return null;
654    }
655
656    /* -- End of RawType methods. -- */
657
658    /* -- Methods that may optionally be overridden by subclasses. -- */
659
660    /**
661     * Called by EntityOutput in rawAccess mode to determine whether an object
662     * type is allowed to be assigned to a given field type.
663     */
664    boolean isAssignableTo(Format format) {
665        if (proxiedFormat != null) {
666            return proxiedFormat.isAssignableTo(format);
667        } else {
668            return format == this ||
669                   format.id == ID_OBJECT ||
670                   supertypes.contains(format.className);
671        }
672    }
673
674    /**
675     * For primitive types only, returns their associated wrapper type.
676     */
677    Format getWrapperFormat() {
678        return null;
679    }
680
681    /**
682     * Returns whether this format class is an entity class.
683     */
684    boolean isEntity() {
685        return false;
686    }
687
688    /**
689     * Returns whether this class is present in the EntityModel.  Returns false
690     * for a simple type, array type, or enum type.
691     */
692    boolean isModelClass() {
693        return false;
694    }
695
696    /**
697     * For an entity class or subclass, returns the base entity class; returns
698     * null in other cases.
699     */
700    ComplexFormat getEntityFormat() {
701        return null;
702    }
703
704    /**
705     * Called for an existing format that may not equal the current format for
706     * the same class.
707     *
708     * <p>If this method returns true, then it must have determined one of two
709     * things:
710     *  - that the old and new formats are equal, and it must have called
711     *  Evolver.useOldFormat; or
712     *  - that the old format can be evolved to the new format, and it must
713     *  have called Evolver.useEvolvedFormat.</p>
714     *
715     * <p>If this method returns false, then it must have determined that the
716     * old format could not be evolved to the new format, and it must have
717     * called Evolver.addInvalidMutation, addMissingMutation or
718     * addEvolveError.</p>
719     */
720    abstract boolean evolve(Format newFormat, Evolver evolver);
721
722    /**
723     * Called when a Converter handles evolution of a class, but we may still
724     * need to evolve the metadata.
725     */
726    boolean evolveMetadata(Format newFormat,
727                           Converter converter,
728                           Evolver evolver) {
729        return true;
730    }
731
732    /**
733     * Returns whether this format is the current format for its class.  If
734     * false is returned, this format is setup to evolve to the current format.
735     */
736    final boolean isCurrentVersion() {
737        return latestFormat == this && !deleted;
738    }
739
740    /**
741     * Returns whether this format has the same class as the given format,
742     * irrespective of version changes and renaming.
743     */
744    final boolean isSameClass(Format other) {
745        return latestFormat == other.latestFormat;
746    }
747
748    /* -- Abstract methods that must be implemented by subclasses. -- */
749
750    /**
751     * Initializes an uninitialized format, initializing its related formats
752     * (superclass formats and array component formats) first.
753     */
754    abstract void initialize(Catalog catalog,
755                             EntityModel model,
756                             int initVersion);
757
758    /**
759     * Calls catalog.createFormat for formats that this format depends on, or
760     * that should also be persistent.
761     */
762    abstract void collectRelatedFormats(Catalog catalog,
763                                        Map<String,Format> newFormats);
764
765    /*
766     * The remaining methods are used to read objects from data bytes via
767     * EntityInput, and to write objects as data bytes via EntityOutput.
768     * Ultimately these methods call methods in the Accessor interface to
769     * get/set fields in the object.  Most methods have a rawAccess parameter
770     * that determines whether the object is a raw object or a real persistent
771     * object.
772     *
773     * The first group of methods are abstract and must be implemented by
774     * format classes.  The second group have default implementations that
775     * throw UnsupportedOperationException and may optionally be overridden.
776     */
777
778    /**
779     * Creates an array of the format's class of the given length, as if
780     * Array.newInstance(getType(), len) were called.  Formats implement this
781     * method for specific classes, or call the accessor, to avoid the
782     * reflection overhead of Array.newInstance.
783     */
784    abstract Object newArray(int len);
785
786    /**
787     * Creates a new instance of the target class using its default
788     * constructor.  Normally this creates an empty object, and readObject() is
789     * called next to fill in the contents.  This is done in two steps to allow
790     * the instance to be registered by EntityInput before reading the
791     * contents.  This allows the fields in an object or a nested object to
792     * refer to the parent object in a graph.
793     *
794     * Alternatively, this method may read all or the first portion of the
795     * data, rather than that being done by readObject().  This is required for
796     * simple types and enums, where the object cannot be created without
797     * reading the data.  In these cases, there is no possibility that the
798     * parent object will be referenced by the child object in the graph.  It
799     * should not be done in other cases, or the graph references may not be
800     * maintained faithfully.
801     *
802     * Is public only in order to implement the Reader interface.  Note that
803     * this method should only be called directly in raw conversion mode or
804     * during conversion of an old format.  Normally it should be called via
805     * the getReader method and the Reader interface.
806     */
807    public abstract Object newInstance(EntityInput input, boolean rawAccess);
808
809    /**
810     * Called after newInstance() to read the rest of the data bytes and fill
811     * in the object contents.  If the object was read completely by
812     * newInstance(), this method does nothing.
813     *
814     * Is public only in order to implement the Reader interface.  Note that
815     * this method should only be called directly in raw conversion mode or
816     * during conversion of an old format.  Normally it should be called via
817     * the getReader method and the Reader interface.
818     */
819    public abstract Object readObject(Object o,
820                                      EntityInput input,
821                                      boolean rawAccess);
822
823    /**
824     * Writes a given instance of the target class to the output data bytes.
825     * This is the complement of the newInstance()/readObject() pair.
826     */
827    abstract void writeObject(Object o, EntityOutput output, boolean rawAccess);
828
829    /**
830     * Skips over the object's contents, as if readObject() were called, but
831     * without returning an object.  Used for extracting secondary key bytes
832     * without having to instantiate the object.  For reference types, the
833     * format ID is read just before calling this method, so this method is
834     * responsible for skipping everything following the format ID.
835     */
836    abstract void skipContents(RecordInput input);
837
838    /* -- More methods that may optionally be overridden by subclasses. -- */
839
840    /**
841     * When extracting a secondary key, called to skip over all fields up to
842     * the given secondary key field.  Returns the format of the key field
843     * found, or null if the field is not present (nullified) in the object.
844     */
845    Format skipToSecKey(RecordInput input, String keyName) {
846        throw new UnsupportedOperationException(toString());
847    }
848
849    /**
850     * Called after skipToSecKey() to copy the data bytes of a singular
851     * (XXX_TO_ONE) key field.
852     */
853    void copySecKey(RecordInput input, RecordOutput output) {
854        throw new UnsupportedOperationException(toString());
855    }
856
857    /**
858     * Called after skipToSecKey() to copy the data bytes of an array or
859     * collection (XXX_TO_MANY) key field.
860     */
861    void copySecMultiKey(RecordInput input, Format keyFormat, Set results) {
862        throw new UnsupportedOperationException(toString());
863    }
864
865    /**
866     * Nullifies the given key field in the given RawObject --  rawAccess mode
867     * is implied.
868     */
869    boolean nullifySecKey(Catalog catalog,
870                          Object entity,
871                          String keyName,
872                          Object keyElement) {
873        throw new UnsupportedOperationException(toString());
874    }
875
876    /**
877     * Returns whether the entity's primary key field is null or zero, as
878     * defined for primary keys that are assigned from a sequence.
879     */
880    boolean isPriKeyNullOrZero(Object o, boolean rawAccess) {
881        throw new UnsupportedOperationException(toString());
882    }
883
884    /**
885     * Gets the primary key field from the given object and writes it to the
886     * given output data bytes.  This is a separate operation because the
887     * primary key data bytes are stored separately from the rest of the
888     * record.
889     */
890    void writePriKey(Object o, EntityOutput output, boolean rawAccess) {
891        throw new UnsupportedOperationException(toString());
892    }
893
894    /**
895     * Reads the primary key from the given input bytes and sets the primary
896     * key field in the given object.  This is complement of writePriKey().
897     *
898     * Is public only in order to implement the Reader interface.  Note that
899     * this method should only be called directly in raw conversion mode or
900     * during conversion of an old format.  Normally it should be called via
901     * the getReader method and the Reader interface.
902     */
903    public void readPriKey(Object o, EntityInput input, boolean rawAccess) {
904        throw new UnsupportedOperationException(toString());
905    }
906
907    /**
908     * Validates and returns the simple integer key format for a sequence key
909     * associated with this format.
910     *
911     * For a composite key type, the format of the one and only field is
912     * returned.  For a simple integer type, this format is returned.
913     * Otherwise (the default implementation), an IllegalArgumentException is
914     * thrown.
915     */
916    Format getSequenceKeyFormat() {
917        throw new IllegalArgumentException
918            ("Type not allowed for sequence: " + getClassName());
919    }
920
921    /**
922     * Converts a RawObject to a current class object and adds the converted
923     * pair to the converted map.
924     */
925    Object convertRawObject(Catalog catalog,
926                            boolean rawAccess,
927                            RawObject rawObject,
928                            IdentityHashMap converted) {
929        throw new UnsupportedOperationException(toString());
930    }
931
932    @Override
933    public String toString() {
934        final String INDENT = "  ";
935        final String INDENT2 = INDENT + "  ";
936        StringBuffer buf = new StringBuffer(500);
937        if (isSimple()) {
938            addTypeHeader(buf, "SimpleType");
939            buf.append(" primitive=\"");
940            buf.append(isPrimitive());
941            buf.append("\"/>\n");
942        } else if (isEnum()) {
943            addTypeHeader(buf, "EnumType");
944            buf.append(">\n");
945            for (String constant : getEnumConstants()) {
946                buf.append(INDENT);
947                buf.append("<Constant>");
948                buf.append(constant);
949                buf.append("</Constant>\n");
950            }
951            buf.append("</EnumType>\n");
952        } else if (isArray()) {
953            addTypeHeader(buf, "ArrayType");
954            buf.append(" componentId=\"");
955            buf.append(getComponentType().getVersion());
956            buf.append("\" componentClass=\"");
957            buf.append(getComponentType().getClassName());
958            buf.append("\" dimensions=\"");
959            buf.append(getDimensions());
960            buf.append("\"/>\n");
961        } else {
962            addTypeHeader(buf, "ComplexType");
963            Format superType = getSuperType();
964            if (superType != null) {
965                buf.append(" superTypeId=\"");
966                buf.append(superType.getId());
967                buf.append("\" superTypeClass=\"");
968                buf.append(superType.getClassName());
969                buf.append('"');
970            }
971            Format proxiedFormat = getProxiedFormat();
972            if (proxiedFormat != null) {
973                buf.append(" proxiedTypeId=\"");
974                buf.append(proxiedFormat.getId());
975                buf.append("\" proxiedTypeClass=\"");
976                buf.append(proxiedFormat.getClassName());
977                buf.append('"');
978            }
979            PrimaryKeyMetadata priMeta = null;
980            Map<String,SecondaryKeyMetadata> secondaryKeys = null;
981            List<FieldMetadata> compositeKeyFields = null;
982            ClassMetadata clsMeta = getClassMetadata();
983            if (clsMeta != null) {
984                compositeKeyFields = clsMeta.getCompositeKeyFields();
985                priMeta = clsMeta.getPrimaryKey();
986                secondaryKeys = clsMeta.getSecondaryKeys();
987            }
988            buf.append(" kind=\"");
989            buf.append(isEntity() ? "entity" :
990                       ((compositeKeyFields != null) ? "compositeKey" :
991                        "persistent"));
992            buf.append("\">\n");
993            Map<String, RawField> fields = getFields();
994            if (fields != null) {
995                for (RawField field : fields.values()) {
996                    String name = field.getName();
997                    RawType type = field.getType();
998                    buf.append(INDENT);
999                    buf.append("<Field");
1000                    buf.append(" name=\"");
1001                    buf.append(name);
1002                    buf.append("\" typeId=\"");
1003                    buf.append(type.getId());
1004                    buf.append("\" typeClass=\"");
1005                    buf.append(type.getClassName());
1006                    buf.append('"');
1007                    if (priMeta != null &&
1008                        priMeta.getName().equals(name)) {
1009                        buf.append(" primaryKey=\"true\"");
1010                        if (priMeta.getSequenceName() != null) {
1011                            buf.append(" sequence=\"");
1012                            buf.append(priMeta.getSequenceName());
1013                            buf.append('"');
1014                        }
1015                    }
1016                    if (secondaryKeys != null) {
1017                        SecondaryKeyMetadata secMeta =
1018                            ComplexFormat.getSecondaryKeyMetadataByFieldName
1019                                (secondaryKeys, name);
1020                        if (secMeta != null) {
1021                            buf.append(" secondaryKey=\"true\" keyName=\"");
1022                            buf.append(secMeta.getKeyName());
1023                            buf.append("\" relate=\"");
1024                            buf.append(secMeta.getRelationship());
1025                            buf.append('"');
1026                            String related = secMeta.getRelatedEntity();
1027                            if (related != null) {
1028                                buf.append("\" relatedEntity=\"");
1029                                buf.append(related);
1030                                buf.append("\" onRelatedEntityDelete=\"");
1031                                buf.append(secMeta.getDeleteAction());
1032                                buf.append('"');
1033                            }
1034                        }
1035                    }
1036                    if (compositeKeyFields != null) {
1037                        int nFields = compositeKeyFields.size();
1038                        for (int i = 0; i < nFields; i += 1) {
1039                            FieldMetadata fldMeta = compositeKeyFields.get(i);
1040                            if (fldMeta.getName().equals(name)) {
1041                                buf.append(" compositeKeyField=\"");
1042                                buf.append(i + 1);
1043                                buf.append('"');
1044                            }
1045                        }
1046                    }
1047                    buf.append("/>\n");
1048                }
1049                EntityMetadata entMeta = getEntityMetadata();
1050                if (entMeta != null) {
1051                    buf.append(INDENT);
1052                    buf.append("<EntityKeys>\n");
1053                    priMeta = entMeta.getPrimaryKey();
1054                    if (priMeta != null) {
1055                        buf.append(INDENT2);
1056                        buf.append("<Primary class=\"");
1057                        buf.append(priMeta.getDeclaringClassName());
1058                        buf.append("\" field=\"");
1059                        buf.append(priMeta.getName());
1060                        buf.append("\"/>\n");
1061                    }
1062                    secondaryKeys = entMeta.getSecondaryKeys();
1063                    if (secondaryKeys != null) {
1064                        for (SecondaryKeyMetadata secMeta :
1065                             secondaryKeys.values()) {
1066                            buf.append(INDENT2);
1067                            buf.append("<Secondary class=\"");
1068                            buf.append(secMeta.getDeclaringClassName());
1069                            buf.append("\" field=\"");
1070                            buf.append(secMeta.getName());
1071                            buf.append("\"/>\n");
1072                        }
1073                    }
1074                    buf.append("</EntityKeys>\n");
1075                }
1076            }
1077            buf.append("</ComplexType>\n");
1078        }
1079        return buf.toString();
1080    }
1081
1082    private void addTypeHeader(StringBuffer buf, String elemName) {
1083        buf.append('<');
1084        buf.append(elemName);
1085        buf.append(" id=\"");
1086        buf.append(getId());
1087        buf.append("\" class=\"");
1088        buf.append(getClassName());
1089        buf.append("\" version=\"");
1090        buf.append(getVersion());
1091        buf.append('"');
1092        Format currVersion = getLatestVersion();
1093        if (currVersion != null) {
1094            buf.append(" currentVersionId=\"");
1095            buf.append(currVersion.getId());
1096            buf.append('"');
1097        }
1098        Format prevVersion = getPreviousVersion();
1099        if (prevVersion != null) {
1100            buf.append(" previousVersionId=\"");
1101            buf.append(prevVersion.getId());
1102            buf.append('"');
1103        }
1104    }
1105}
1106