1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 * $Id: ComplexFormat.java,v 1.1 2008/02/07 17:12:27 mark Exp $
7 */
8
9package com.sleepycat.persist.impl;
10
11import java.io.Serializable;
12import java.util.ArrayList;
13import java.util.Collections;
14import java.util.HashMap;
15import java.util.HashSet;
16import java.util.IdentityHashMap;
17import java.util.List;
18import java.util.Map;
19import java.util.Set;
20
21import com.sleepycat.persist.evolve.Converter;
22import com.sleepycat.persist.evolve.Deleter;
23import com.sleepycat.persist.evolve.EntityConverter;
24import com.sleepycat.persist.evolve.Mutations;
25import com.sleepycat.persist.evolve.Renamer;
26import com.sleepycat.persist.model.ClassMetadata;
27import com.sleepycat.persist.model.EntityMetadata;
28import com.sleepycat.persist.model.FieldMetadata;
29import com.sleepycat.persist.model.Relationship;
30import com.sleepycat.persist.model.SecondaryKeyMetadata;
31import com.sleepycat.persist.raw.RawField;
32import com.sleepycat.persist.raw.RawObject;
33
34/**
35 * Format for persistent complex classes that are not composite key classes.
36 * This includes entity classes and subclasses.
37 *
38 * @author Mark Hayes
39 */
40public class ComplexFormat extends Format {
41
42    private static final long serialVersionUID = -2847843033590454917L;
43
44    private ClassMetadata clsMeta;
45    private EntityMetadata entityMeta;
46    private FieldInfo priKeyField;
47    private List<FieldInfo> secKeyFields;
48    private List<FieldInfo> nonKeyFields;
49    private FieldReader secKeyFieldReader;
50    private FieldReader nonKeyFieldReader;
51    private Map<String,String> oldToNewKeyMap;
52    private Map<String,String> newToOldFieldMap;
53    private boolean evolveNeeded;
54    private transient Accessor objAccessor;
55    private transient Accessor rawAccessor;
56    private transient Format entityFormat;
57    private transient Map<String,FieldAddress> secKeyAddresses;
58    private transient volatile Map<String,RawField> rawFields;
59    private transient volatile FieldInfo[] rawInputFields;
60    private transient volatile int[] rawInputLevels;
61    private transient volatile int rawInputDepth;
62
63    ComplexFormat(Class cls,
64                  ClassMetadata clsMeta,
65                  EntityMetadata entityMeta) {
66        super(cls);
67        this.clsMeta = clsMeta;
68        this.entityMeta = entityMeta;
69        secKeyFields = new ArrayList<FieldInfo>();
70        nonKeyFields = FieldInfo.getInstanceFields(cls);
71
72        /*
73         * Validate primary key metadata and move primary key field from
74         * nonKeyFields to priKeyField.
75         */
76        if (clsMeta.getPrimaryKey() != null) {
77            String fieldName = clsMeta.getPrimaryKey().getName();
78            FieldInfo field = FieldInfo.getField(nonKeyFields, fieldName);
79            if (field == null) {
80                throw new IllegalArgumentException
81                    ("Primary key field does not exist: " +
82                     getClassName() + '.' + fieldName);
83            }
84            nonKeyFields.remove(field);
85            priKeyField = field;
86        }
87
88        /*
89         * Validate secondary key metadata and move secondary key fields from
90         * nonKeyFields to secKeyFields.
91         */
92        if (clsMeta.getSecondaryKeys() != null) {
93            for (SecondaryKeyMetadata secKeyMeta :
94                 clsMeta.getSecondaryKeys().values()) {
95                String fieldName = secKeyMeta.getName();
96                FieldInfo field = FieldInfo.getField(nonKeyFields, fieldName);
97                if (field == null) {
98                    throw new IllegalArgumentException
99                        ("Secondary key field does not exist: " +
100                         getClassName() + '.' + fieldName);
101                }
102                Class fieldCls = field.getFieldClass();
103                Relationship rel = secKeyMeta.getRelationship();
104                if (rel == Relationship.ONE_TO_MANY ||
105                    rel == Relationship.MANY_TO_MANY) {
106                    if (!PersistKeyCreator.isManyType(fieldCls)) {
107                        throw new IllegalArgumentException
108                            ("ONE_TO_MANY and MANY_TO_MANY keys must" +
109                             " have an array or Collection type: " +
110                             getClassName() + '.' + fieldName);
111                    }
112                } else {
113                    if (PersistKeyCreator.isManyType(fieldCls)) {
114                        throw new IllegalArgumentException
115                            ("ONE_TO_ONE and MANY_TO_ONE keys must not" +
116                             " have an array or Collection type: " +
117                             getClassName() + '.' + fieldName);
118                    }
119                }
120                nonKeyFields.remove(field);
121                secKeyFields.add(field);
122            }
123        }
124
125        /* Sort each group of fields by name. */
126        Collections.sort(secKeyFields);
127        Collections.sort(nonKeyFields);
128    }
129
130    @Override
131    void migrateFromBeta(Map<String,Format> formatMap) {
132        super.migrateFromBeta(formatMap);
133        if (priKeyField != null) {
134            priKeyField.migrateFromBeta(formatMap);
135        }
136        for (FieldInfo field : secKeyFields) {
137            field.migrateFromBeta(formatMap);
138        }
139        for (FieldInfo field : nonKeyFields) {
140            field.migrateFromBeta(formatMap);
141        }
142    }
143
144    /**
145     * Returns getSuperFormat cast to ComplexFormat.  It is guaranteed that all
146     * super formats of a ComplexFormat are a ComplexFormat.
147     */
148    private ComplexFormat getComplexSuper() {
149        return (ComplexFormat) getSuperFormat();
150    }
151
152    /**
153     * Returns getLatestVersion cast to ComplexFormat.  It is guaranteed that
154     * all versions of a ComplexFormat are a ComplexFormat.
155     */
156    private ComplexFormat getComplexLatest() {
157        return (ComplexFormat) getLatestVersion();
158    }
159
160    String getPriKeyField() {
161        if (clsMeta.getPrimaryKey() != null) {
162            return clsMeta.getPrimaryKey().getName();
163        } else {
164            return null;
165        }
166    }
167
168    @Override
169    boolean isEntity() {
170        return clsMeta.isEntityClass();
171    }
172
173    @Override
174    boolean isModelClass() {
175        return true;
176    }
177
178    @Override
179    ClassMetadata getClassMetadata() {
180        return clsMeta;
181    }
182
183    @Override
184    EntityMetadata getEntityMetadata() {
185        return entityMeta;
186    }
187
188    @Override
189    Format getEntityFormat() {
190        if (isInitialized()) {
191            return entityFormat;
192        } else {
193            for (Format format = this;
194                 format != null;
195                 format = format.getSuperFormat()) {
196                if (format.isEntity()) {
197                    return format;
198                }
199            }
200            return null;
201        }
202    }
203
204    @Override
205    void setEvolveNeeded(boolean needed) {
206        evolveNeeded = needed;
207    }
208
209    @Override
210    boolean getEvolveNeeded() {
211        return evolveNeeded;
212    }
213
214    @Override
215    public Map<String,RawField> getFields() {
216
217        /*
218         * Synchronization is not required since rawFields is immutable.  If
219         * by chance we create two maps when two threads execute this block, no
220         * harm is done.  But be sure to assign the rawFields field only after
221         * the map is fully populated.
222         */
223        if (rawFields == null) {
224            Map<String,RawField> map = new HashMap<String,RawField>();
225            if (priKeyField != null) {
226                map.put(priKeyField.getName(), priKeyField);
227            }
228            for (RawField field : secKeyFields) {
229                map.put(field.getName(), field);
230            }
231            for (RawField field : nonKeyFields) {
232                map.put(field.getName(), field);
233            }
234            rawFields = map;
235        }
236        return rawFields;
237    }
238
239    @Override
240    void collectRelatedFormats(Catalog catalog,
241                               Map<String,Format> newFormats) {
242        Class cls = getType();
243        /* Collect field formats. */
244        if (priKeyField != null) {
245            priKeyField.collectRelatedFormats(catalog, newFormats);
246        }
247        for (FieldInfo field : secKeyFields) {
248            field.collectRelatedFormats(catalog, newFormats);
249        }
250        for (FieldInfo field : nonKeyFields) {
251            field.collectRelatedFormats(catalog, newFormats);
252        }
253        /* Collect TO_MANY secondary key field element class formats. */
254        if (entityMeta != null) {
255            for (SecondaryKeyMetadata secKeyMeta :
256                 entityMeta.getSecondaryKeys().values()) {
257                String elemClsName = secKeyMeta.getElementClassName();
258                if (elemClsName != null) {
259                    Class elemCls =
260                        SimpleCatalog.keyClassForName(elemClsName);
261                    catalog.createFormat(elemCls, newFormats);
262                }
263            }
264        }
265        /* Recursively collect superclass formats. */
266        Class superCls = cls.getSuperclass();
267        if (superCls != Object.class) {
268            Format superFormat = catalog.createFormat(superCls, newFormats);
269            if (!(superFormat instanceof ComplexFormat)) {
270                throw new IllegalArgumentException
271                    ("The superclass of a complex type must not be a" +
272                     " composite key class or a simple type class: " +
273                     superCls.getName());
274            }
275        }
276        /* Collect proxied format. */
277        String proxiedClsName = clsMeta.getProxiedClassName();
278        if (proxiedClsName != null) {
279            catalog.createFormat(proxiedClsName, newFormats);
280        }
281    }
282
283    @Override
284    void initialize(Catalog catalog, int initVersion) {
285        Class type = getType();
286        boolean useEnhanced = false;
287        if (type != null) {
288            useEnhanced = EnhancedAccessor.isEnhanced(type);
289        }
290        /* Initialize all fields. */
291        if (priKeyField != null) {
292            priKeyField.initialize(catalog, initVersion);
293        }
294        for (FieldInfo field : secKeyFields) {
295            field.initialize(catalog, initVersion);
296        }
297        for (FieldInfo field : nonKeyFields) {
298            field.initialize(catalog, initVersion);
299        }
300        /* Set the superclass format for a new (never initialized) format. */
301        ComplexFormat superFormat = getComplexSuper();
302        if (type != null && superFormat == null) {
303            Class superCls = type.getSuperclass();
304            if (superCls != Object.class) {
305                superFormat =
306                    (ComplexFormat) catalog.getFormat(superCls.getName());
307                setSuperFormat(superFormat);
308            }
309        }
310        /* Initialize the superclass format and validate the super accessor. */
311        if (superFormat != null) {
312            superFormat.initializeIfNeeded(catalog);
313            Accessor superAccessor = superFormat.objAccessor;
314            if (type != null && superAccessor != null) {
315                if (useEnhanced) {
316                    if (!(superAccessor instanceof EnhancedAccessor)) {
317                        throw new IllegalStateException
318                            ("The superclass of an enhanced class must also " +
319                             "be enhanced: " + getClassName() +
320                             " extends " + superFormat.getClassName());
321                    }
322                } else {
323                    if (!(superAccessor instanceof ReflectionAccessor)) {
324                        throw new IllegalStateException
325                            ("The superclass of an unenhanced class must " +
326                             "not be enhanced: " + getClassName() +
327                             " extends " + superFormat.getClassName());
328                    }
329                }
330            }
331        }
332        /* Find entity format, if any. */
333        for (Format format = this;
334             format != null;
335             format = format.getSuperFormat()) {
336            if (format.isEntity()) {
337                entityFormat = format;
338                break;
339            }
340        }
341        /* Disallow primary keys on entity subclasses.  [#15757] */
342        if (entityFormat != null &&
343            entityFormat != this &&
344            priKeyField != null) {
345            throw new IllegalArgumentException
346                ("A PrimaryKey may not appear on an Entity subclass: " +
347                 getClassName() + " field: " + priKeyField.getName());
348        }
349        /* Create the accessors. */
350        if (type != null) {
351            if (useEnhanced) {
352                objAccessor = new EnhancedAccessor(catalog, type, this);
353            } else {
354                Accessor superObjAccessor =
355                    (superFormat != null) ?  superFormat.objAccessor : null;
356                objAccessor = new ReflectionAccessor
357                    (catalog, type, superObjAccessor, priKeyField,
358                     secKeyFields, nonKeyFields);
359            }
360        }
361        Accessor superRawAccessor =
362            (superFormat != null) ? superFormat.rawAccessor : null;
363        rawAccessor = new RawAccessor
364            (this, superRawAccessor, priKeyField, secKeyFields, nonKeyFields);
365
366        /* Initialize secondary key field addresses. */
367        EntityMetadata latestEntityMeta = null;
368        if (entityFormat != null) {
369            latestEntityMeta =
370                entityFormat.getLatestVersion().getEntityMetadata();
371        }
372        if (latestEntityMeta != null) {
373            secKeyAddresses = new HashMap<String,FieldAddress>();
374            ComplexFormat thisLatest = getComplexLatest();
375            if (thisLatest != this) {
376                thisLatest.initializeIfNeeded(catalog);
377            }
378            nextKeyLoop:
379            for (SecondaryKeyMetadata secKeyMeta :
380                 latestEntityMeta.getSecondaryKeys().values()) {
381                String clsName = secKeyMeta.getDeclaringClassName();
382                String fieldName = secKeyMeta.getName();
383                int superLevel = 0;
384                for (ComplexFormat format = this;
385                     format != null;
386                     format = format.getComplexSuper()) {
387                    if (clsName.equals
388                            (format.getLatestVersion().getClassName())) {
389                        String useFieldName = null;
390                        if (format.newToOldFieldMap != null &&
391                            format.newToOldFieldMap.containsKey(fieldName)) {
392                            useFieldName =
393                                format.newToOldFieldMap.get(fieldName);
394                        } else {
395                            useFieldName = fieldName;
396                        }
397                        boolean isSecField;
398                        int fieldNum;
399                        FieldInfo info = FieldInfo.getField
400                            (format.secKeyFields, useFieldName);
401                        if (info != null) {
402                            isSecField = true;
403                            fieldNum = format.secKeyFields.indexOf(info);
404                        } else {
405                            isSecField = false;
406                            info = FieldInfo.getField
407                                (format.nonKeyFields, useFieldName);
408                            if (info == null) {
409                                /* Field not present in old format. */
410                                assert thisLatest != this;
411                                thisLatest.checkNewSecKeyInitializer
412                                    (secKeyMeta);
413                                continue nextKeyLoop;
414                            }
415                            fieldNum = format.nonKeyFields.indexOf(info);
416                        }
417                        FieldAddress addr = new FieldAddress
418                            (isSecField, fieldNum, superLevel, format,
419                             info.getType());
420                        secKeyAddresses.put(secKeyMeta.getKeyName(), addr);
421                    }
422                    superLevel += 1;
423                }
424            }
425        }
426    }
427
428    /**
429     * Checks that the type of a new secondary key is not a primitive and that
430     * the default contructor does not initialize it to a non-null value.
431     */
432    private void checkNewSecKeyInitializer(SecondaryKeyMetadata secKeyMeta) {
433        if (objAccessor != null) {
434            FieldAddress addr = secKeyAddresses.get(secKeyMeta.getKeyName());
435            Object obj = objAccessor.newInstance();
436            Object val = objAccessor.getField
437                (obj, addr.fieldNum, addr.superLevel, addr.isSecField);
438            if (val != null) {
439                if (addr.keyFormat.isPrimitive()) {
440                    throw new IllegalArgumentException
441                        ("For a new secondary key field the field type must " +
442                         "not be a primitive -- class: " +
443                         secKeyMeta.getDeclaringClassName() + " field: " +
444                         secKeyMeta.getName());
445                } else {
446                    throw new IllegalArgumentException
447                        ("For a new secondary key field the default " +
448                         "constructor must not initialize the field to a " +
449                         "non-null value -- class: " +
450                         secKeyMeta.getDeclaringClassName() + " field: " +
451                         secKeyMeta.getName());
452                }
453            }
454        }
455    }
456
457    private boolean nullOrEqual(Object o1, Object o2) {
458        if (o1 == null) {
459            return o2 == null;
460        } else {
461            return o1.equals(o2);
462        }
463    }
464
465    @Override
466    Object newArray(int len) {
467        return objAccessor.newArray(len);
468    }
469
470    @Override
471    public Object newInstance(EntityInput input, boolean rawAccess) {
472        Accessor accessor = rawAccess ? rawAccessor : objAccessor;
473        return accessor.newInstance();
474    }
475
476    @Override
477    public Object readObject(Object o, EntityInput input, boolean rawAccess) {
478        Accessor accessor = rawAccess ? rawAccessor : objAccessor;
479        accessor.readSecKeyFields(o, input, 0, Accessor.MAX_FIELD_NUM, -1);
480        accessor.readNonKeyFields(o, input, 0, Accessor.MAX_FIELD_NUM, -1);
481        return o;
482    }
483
484    @Override
485    void writeObject(Object o, EntityOutput output, boolean rawAccess) {
486        Accessor accessor = rawAccess ? rawAccessor : objAccessor;
487        accessor.writeSecKeyFields(o, output);
488        accessor.writeNonKeyFields(o, output);
489    }
490
491    @Override
492    Object convertRawObject(Catalog catalog,
493                            boolean rawAccess,
494                            RawObject rawObject,
495                            IdentityHashMap converted) {
496        /*
497         * Synchronization is not required since rawInputFields, rawInputLevels
498         * and rawInputDepth are immutable.  If by chance we create duplicate
499         * values when two threads execute this block, no harm is done.  But be
500         * sure to assign the fields only after the values are fully populated.
501         */
502        FieldInfo[] fields = rawInputFields;
503        int[] levels = rawInputLevels;
504        int depth = rawInputDepth;
505        if (fields == null || levels == null || depth == 0) {
506
507            /*
508             * The volatile fields are not yet set.  Prepare to process the
509             * class hierarchy, storing class formats in order from the highest
510             * superclass down to the current class.
511             */
512            depth = 0;
513            int nFields = 0;
514            for (ComplexFormat format = this;
515                 format != null;
516                 format = format.getComplexSuper()) {
517                nFields += format.getNFields();
518                depth += 1;
519            }
520            ComplexFormat[] hierarchy = new ComplexFormat[depth];
521            int level = depth;
522            for (ComplexFormat format = this;
523                 format != null;
524                 format = format.getComplexSuper()) {
525                level -= 1;
526                hierarchy[level] = format;
527            }
528            assert level == 0;
529
530            /* Populate levels and fields in parallel. */
531            levels = new int[nFields];
532            fields = new FieldInfo[nFields];
533            int index = 0;
534
535            /*
536             * The primary key is the first field read/written.  We use the
537             * first primary key field encountered going from this class upward
538             * in the class hierarchy.
539             */
540            if (getEntityFormat() != null) {
541                for (level = depth - 1; level >= 0; level -= 1) {
542                    ComplexFormat format = hierarchy[level];
543                    if (format.priKeyField != null) {
544                        levels[index] = level;
545                        fields[index] = format.priKeyField;
546                        index += 1;
547                        break;
548                    }
549                }
550                assert index == 1;
551            }
552
553            /*
554             * Secondary key fields are read/written next, from the highest
555             * base class downward.
556             */
557            for (level = 0; level < depth; level += 1) {
558                ComplexFormat format = hierarchy[level];
559                for (FieldInfo field : format.secKeyFields) {
560                    levels[index] = level;
561                    fields[index] = field;
562                    index += 1;
563                }
564            }
565
566            /*
567             * Other fields are read/written last, from the highest base class
568             * downward.
569             */
570            for (level = 0; level < depth; level += 1) {
571                ComplexFormat format = hierarchy[level];
572                for (FieldInfo field : format.nonKeyFields) {
573                    levels[index] = level;
574                    fields[index] = field;
575                    index += 1;
576                }
577            }
578
579            /* We're finished -- update the volatile fields for next time. */
580            assert index == fields.length;
581            rawInputFields = fields;
582            rawInputLevels = levels;
583            rawInputDepth = depth;
584        }
585
586        /*
587         * Create an objects array that is parallel to the fields and levels
588         * arrays, but contains the RawObject for each slot from which the
589         * field value can be retrieved.  The predetermined level for each
590         * field determines which RawObject in the instance hierarchy to use.
591         */
592        RawObject[] objectsByLevel = new RawObject[depth];
593        int level = depth;
594        for (RawObject raw = rawObject; raw != null; raw = raw.getSuper()) {
595            if (level == 0) {
596                throw new IllegalArgumentException
597                    ("RawObject has too many superclasses: " +
598                     rawObject.getType().getClassName());
599            }
600            level -= 1;
601            objectsByLevel[level] = raw;
602        }
603        if (level > 0) {
604            throw new IllegalArgumentException
605                ("RawObject has too few superclasses: " +
606                 rawObject.getType().getClassName());
607        }
608        assert level == 0;
609        RawObject[] objects = new RawObject[fields.length];
610        for (int i = 0; i < objects.length; i += 1) {
611            objects[i] = objectsByLevel[levels[i]];
612        }
613
614        /* Create the persistent object and convert all RawObject fields. */
615        EntityInput in = new RawComplexInput
616            (catalog, rawAccess, converted, fields, objects);
617        Object o = newInstance(in, rawAccess);
618        converted.put(rawObject, o);
619        if (getEntityFormat() != null) {
620            readPriKey(o, in, rawAccess);
621        }
622        return readObject(o, in, rawAccess);
623    }
624
625    @Override
626    boolean isPriKeyNullOrZero(Object o, boolean rawAccess) {
627        Accessor accessor = rawAccess ? rawAccessor : objAccessor;
628        return accessor.isPriKeyFieldNullOrZero(o);
629    }
630
631    @Override
632    void writePriKey(Object o, EntityOutput output, boolean rawAccess) {
633        Accessor accessor = rawAccess ? rawAccessor : objAccessor;
634        accessor.writePriKeyField(o, output);
635    }
636
637    @Override
638    public void readPriKey(Object o, EntityInput input, boolean rawAccess) {
639        Accessor accessor = rawAccess ? rawAccessor : objAccessor;
640        accessor.readPriKeyField(o, input);
641    }
642
643    @Override
644    boolean nullifySecKey(Catalog catalog,
645                          Object entity,
646                          String keyName,
647                          Object keyElement) {
648        if (secKeyAddresses == null) {
649            throw new IllegalStateException();
650        }
651        FieldAddress addr = secKeyAddresses.get(keyName);
652        if (addr != null) {
653            Object oldVal = rawAccessor.getField
654                (entity, addr.fieldNum, addr.superLevel, addr.isSecField);
655            if (oldVal != null) {
656                if (keyElement != null) {
657                    RawObject container = (RawObject) oldVal;
658                    Object[] a1 = container.getElements();
659                    boolean isArray = (a1 != null);
660                    if (!isArray) {
661                        a1 = CollectionProxy.getElements(container);
662                    }
663                    if (a1 != null) {
664                        for (int i = 0; i < a1.length; i += 1) {
665                            if (keyElement.equals(a1[i])) {
666                                int len = a1.length - 1;
667                                Object[] a2 = new Object[len];
668                                System.arraycopy(a1, 0, a2, 0, i);
669                                System.arraycopy(a1, i + 1, a2, i, len - i);
670                                if (isArray) {
671                                    rawAccessor.setField
672                                        (entity, addr.fieldNum,
673                                         addr.superLevel, addr.isSecField,
674                                         new RawObject
675                                            (container.getType(), a2));
676                                } else {
677                                    CollectionProxy.setElements(container, a2);
678                                }
679                                return true;
680                            }
681                        }
682                    }
683                    return false;
684                } else {
685                    rawAccessor.setField
686                        (entity, addr.fieldNum, addr.superLevel,
687                         addr.isSecField, null);
688                    return true;
689                }
690            } else {
691                return false;
692            }
693        } else {
694            return false;
695        }
696    }
697
698    @Override
699    void skipContents(RecordInput input) {
700        skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
701        skipToNonKeyField(input, Accessor.MAX_FIELD_NUM);
702    }
703
704    @Override
705    void copySecMultiKey(RecordInput input, Format keyFormat, Set results) {
706        CollectionProxy.copyElements(input, this, keyFormat, results);
707    }
708
709    @Override
710    Format skipToSecKey(RecordInput input, String keyName) {
711        if (secKeyAddresses == null) {
712            throw new IllegalStateException();
713        }
714        FieldAddress addr = secKeyAddresses.get(keyName);
715        if (addr != null) {
716            if (addr.isSecField) {
717                addr.clsFormat.skipToSecKeyField(input, addr.fieldNum);
718            } else {
719                skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
720                addr.clsFormat.skipToNonKeyField(input, addr.fieldNum);
721            }
722            return addr.keyFormat;
723        } else {
724            return null;
725        }
726    }
727
728    private int getNFields() {
729        return ((priKeyField != null) ? 1 : 0) +
730               secKeyFields.size() +
731               nonKeyFields.size();
732    }
733
734    private void skipToSecKeyField(RecordInput input, int toFieldNum) {
735        ComplexFormat superFormat = getComplexSuper();
736        if (superFormat != null) {
737            superFormat.skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
738        }
739        int maxNum = Math.min(secKeyFields.size(), toFieldNum);
740        for (int i = 0; i < maxNum; i += 1) {
741            input.skipField(secKeyFields.get(i).getType());
742        }
743    }
744
745    private void skipToNonKeyField(RecordInput input, int toFieldNum) {
746        ComplexFormat superFormat = getComplexSuper();
747        if (superFormat != null) {
748            superFormat.skipToNonKeyField(input, Accessor.MAX_FIELD_NUM);
749        }
750        int maxNum = Math.min(nonKeyFields.size(), toFieldNum);
751        for (int i = 0; i < maxNum; i += 1) {
752            input.skipField(nonKeyFields.get(i).getType());
753        }
754    }
755
756    private static class FieldAddress {
757
758        boolean isSecField;
759        int fieldNum;
760        int superLevel;
761        ComplexFormat clsFormat;
762        Format keyFormat;
763
764        FieldAddress(boolean isSecField,
765                     int fieldNum,
766                     int superLevel,
767                     ComplexFormat clsFormat,
768                     Format keyFormat) {
769            this.isSecField = isSecField;
770            this.fieldNum = fieldNum;
771            this.superLevel = superLevel;
772            this.clsFormat = clsFormat;
773            this.keyFormat = keyFormat;
774        }
775    }
776
777    @Override
778    boolean evolve(Format newFormatParam, Evolver evolver) {
779
780        /* Disallow evolution to a non-complex format. */
781        if (!(newFormatParam instanceof ComplexFormat)) {
782            evolver.addMissingMutation
783                (this, newFormatParam,
784                 "Converter is required when a complex type is changed " +
785                 "to a simple type or enum type");
786            return false;
787        }
788        ComplexFormat newFormat = (ComplexFormat) newFormatParam;
789        Mutations mutations = evolver.getMutations();
790        boolean thisChanged = false;
791        boolean superChanged = false;
792        Map<String,String> allKeyNameMap = new HashMap<String,String>();
793
794        /*
795         * Evolve all superclass formats, even when a deleted class appears in
796         * the hierarchy.  This ensures that the super format's
797         * getLatestVersion/getComplexLatest method can be used accurately
798         * below.
799         */
800        for (ComplexFormat oldSuper = getComplexSuper();
801             oldSuper != null;
802             oldSuper = oldSuper.getComplexSuper()) {
803            Converter converter = mutations.getConverter
804                (oldSuper.getClassName(), oldSuper.getVersion(), null);
805            if (converter != null) {
806                evolver.addMissingMutation
807                    (this, newFormatParam,
808                     "Converter is required for this subclass when a " +
809                     "Converter appears on its superclass: " + converter);
810                return false;
811            }
812            if (!evolver.evolveFormat(oldSuper)) {
813                return false;
814            }
815            if (!oldSuper.isCurrentVersion()) {
816                if (oldSuper.isDeleted()) {
817                    if (!oldSuper.evolveDeletedClass(evolver)) {
818                        return false;
819                    }
820                }
821                if (oldSuper.oldToNewKeyMap != null) {
822                    allKeyNameMap.putAll(oldSuper.oldToNewKeyMap);
823                }
824                superChanged = true;
825            }
826        }
827
828        /*
829         * Compare the old and new class hierarhies and decide whether each
830         * change is allowed or not:
831         * + Old deleted and removed superclass -- allowed
832         * + Old empty and removed superclass -- allowed
833         * + Old non-empty and removed superclass -- not allowed
834         * + Old superclass repositioned in the hierarchy -- not allowed
835         * + New inserted superclass -- allowed
836         */
837        Class newFormatCls = newFormat.getExistingType();
838        Class newSuper = newFormatCls;
839        List<Integer> newLevels = new ArrayList<Integer>();
840        int newLevel = 0;
841        newLevels.add(newLevel);
842
843        /*
844         * When this format has a new superclass, we treat it as a change to
845         * this format as well as to the superclass hierarchy.
846         */
847        if (getSuperFormat() == null) {
848            if (newFormatCls.getSuperclass() != Object.class) {
849                thisChanged = true;
850                superChanged = true;
851            }
852        } else {
853            if (!getSuperFormat().getLatestVersion().getClassName().equals
854                    (newFormatCls.getSuperclass().getName())) {
855                thisChanged = true;
856                superChanged = true;
857            }
858        }
859
860        for (ComplexFormat oldSuper = getComplexSuper();
861             oldSuper != null;
862             oldSuper = oldSuper.getComplexSuper()) {
863
864            /* Find the matching superclass in the new hierarchy. */
865            String oldSuperName = oldSuper.getLatestVersion().getClassName();
866            Class foundNewSuper = null;
867            int tryNewLevel = newLevel;
868            for (Class newSuper2 = newSuper.getSuperclass();
869                 newSuper2 != Object.class;
870                 newSuper2 = newSuper2.getSuperclass()) {
871                tryNewLevel += 1;
872                if (oldSuperName.equals(newSuper2.getName())) {
873                    foundNewSuper = newSuper2;
874                    newLevel = tryNewLevel;
875                    break;
876                }
877            }
878
879            if (foundNewSuper != null) {
880
881                /*
882                 * We found the old superclass in the new hierarchy.  Traverse
883                 * through the superclass formats that were skipped over above
884                 * when finding it.
885                 */
886                for (Class newSuper2 = newSuper.getSuperclass();
887                     newSuper2 != foundNewSuper;
888                     newSuper2 = newSuper2.getSuperclass()) {
889
890                    /*
891                     * The class hierarchy changed -- a new class was inserted.
892                     */
893                    superChanged = true;
894
895                    /*
896                     * Check that the new formats skipped over above are not at
897                     * a different position in the old hierarchy.
898                     */
899                    for (ComplexFormat oldSuper2 = oldSuper.getComplexSuper();
900                         oldSuper2 != null;
901                         oldSuper2 = oldSuper2.getComplexSuper()) {
902                        String oldSuper2Name =
903                            oldSuper2.getLatestVersion().getClassName();
904                        if (oldSuper2Name.equals(newSuper2.getName())) {
905                            evolver.addMissingMutation
906                                (this, newFormatParam,
907                                 "Class Converter is required when a " +
908                                 "superclass is moved in the class " +
909                                 "hierarchy: " + newSuper2.getName());
910                            return false;
911                        }
912                    }
913                }
914                newSuper = foundNewSuper;
915                newLevels.add(newLevel);
916            } else {
917
918                /*
919                 * We did not find the old superclass in the new hierarchy.
920                 * The class hierarchy changed, since an old class no longer
921                 * appears.
922                 */
923                superChanged = true;
924
925                /* Check that the old class can be safely removed. */
926                if (!oldSuper.isDeleted()) {
927                    ComplexFormat oldSuperLatest =
928                        oldSuper.getComplexLatest();
929                    if (oldSuperLatest.getNFields() != 0) {
930                        evolver.addMissingMutation
931                            (this, newFormatParam,
932                             "When a superclass is removed from the class " +
933                             "hierarchy, the superclass or all of its " +
934                             "persistent fields must be deleted with a " +
935                             "Deleter: " +
936                             oldSuperLatest.getClassName());
937                        return false;
938                    }
939                }
940
941                if (isEntity() && isCurrentVersion()) {
942                    Map<String,SecondaryKeyMetadata> secKeys =
943                        oldSuper.clsMeta.getSecondaryKeys();
944                    for (FieldInfo field : oldSuper.secKeyFields) {
945                        SecondaryKeyMetadata meta =
946                            secKeys.get(field.getName());
947                        assert meta != null;
948                        allKeyNameMap.put(meta.getKeyName(), null);
949                    }
950                }
951
952                /*
953                 * Add the DO_NOT_READ_ACCESSOR level to prevent an empty class
954                 * (no persistent fields) from being read via the Accessor.
955                 */
956                newLevels.add(EvolveReader.DO_NOT_READ_ACCESSOR);
957            }
958        }
959
960        /* Make FieldReaders for this format if needed. */
961        int result = evolveAllFields(newFormat, evolver);
962        if (result == Evolver.EVOLVE_FAILURE) {
963            return false;
964        }
965        if (result == Evolver.EVOLVE_NEEDED) {
966            thisChanged = true;
967        }
968        if (oldToNewKeyMap != null) {
969            allKeyNameMap.putAll(oldToNewKeyMap);
970        }
971
972        /* Require new version number if this class was changed. */
973        if (thisChanged &&
974            !evolver.checkUpdatedVersion
975                ("Changes to the fields or superclass were detected", this,
976                 newFormat)) {
977            return false;
978        }
979
980        /* Rename the secondary databases. */
981        if (allKeyNameMap.size() > 0 && isEntity() && isCurrentVersion()) {
982            for (Map.Entry<String,String> entry : allKeyNameMap.entrySet()) {
983                 String oldKeyName = entry.getKey();
984                 String newKeyName = entry.getValue();
985                if (newKeyName != null) {
986                    evolver.renameSecondaryDatabase
987                        (this, newFormat, oldKeyName, newKeyName);
988                } else {
989                    evolver.deleteSecondaryDatabase(this, oldKeyName);
990                }
991            }
992        }
993
994        /* Use an EvolveReader if needed. */
995        if (superChanged || thisChanged) {
996            Reader reader = new EvolveReader(newLevels);
997            evolver.useEvolvedFormat(this, reader, newFormat);
998        } else {
999            evolver.useOldFormat(this, newFormat);
1000        }
1001        return true;
1002    }
1003
1004    @Override
1005    boolean evolveMetadata(Format newFormatParam,
1006                           Converter converter,
1007                           Evolver evolver) {
1008        assert !isDeleted();
1009        assert isEntity();
1010        assert newFormatParam.isEntity();
1011        ComplexFormat newFormat = (ComplexFormat) newFormatParam;
1012
1013        if (!checkKeyTypeChange
1014                (newFormat, entityMeta.getPrimaryKey(),
1015                 newFormat.entityMeta.getPrimaryKey(), "primary key",
1016                 evolver)) {
1017            return false;
1018        }
1019
1020        Set<String> deletedKeys;
1021        if (converter instanceof EntityConverter) {
1022            EntityConverter entityConverter = (EntityConverter) converter;
1023            deletedKeys = entityConverter.getDeletedKeys();
1024        } else {
1025            deletedKeys = Collections.emptySet();
1026        }
1027
1028        Map<String,SecondaryKeyMetadata> oldSecondaryKeys =
1029            entityMeta.getSecondaryKeys();
1030        Map<String,SecondaryKeyMetadata> newSecondaryKeys =
1031            newFormat.entityMeta.getSecondaryKeys();
1032        Set<String> insertedKeys =
1033            new HashSet<String>(newSecondaryKeys.keySet());
1034
1035        for (SecondaryKeyMetadata oldMeta : oldSecondaryKeys.values()) {
1036            String keyName = oldMeta.getKeyName();
1037            if (deletedKeys.contains(keyName)) {
1038                if (isCurrentVersion()) {
1039                    evolver.deleteSecondaryDatabase(this, keyName);
1040                }
1041            } else {
1042                SecondaryKeyMetadata newMeta = newSecondaryKeys.get(keyName);
1043                if (newMeta == null) {
1044                    evolver.addInvalidMutation
1045                        (this, newFormat, converter,
1046                         "Existing key not found in new entity metadata: " +
1047                          keyName);
1048                    return false;
1049                }
1050                insertedKeys.remove(keyName);
1051                String keyLabel = "secondary key: " + keyName;
1052                if (!checkKeyTypeChange
1053                        (newFormat, oldMeta, newMeta, keyLabel, evolver)) {
1054                    return false;
1055                }
1056                if (!checkSecKeyMetadata
1057                        (newFormat, oldMeta, newMeta, evolver)) {
1058                    return false;
1059                }
1060            }
1061        }
1062
1063        if (!insertedKeys.isEmpty()) {
1064            evolver.addEvolveError
1065                (this, newFormat, "Error",
1066                 "New keys " + insertedKeys +
1067                 " not allowed when using a Converter with an entity class");
1068        }
1069
1070        return true;
1071    }
1072
1073    /**
1074     * Checks that changes to secondary key metadata are legal.
1075     */
1076    private boolean checkSecKeyMetadata(Format newFormat,
1077                                        SecondaryKeyMetadata oldMeta,
1078                                        SecondaryKeyMetadata newMeta,
1079                                        Evolver evolver) {
1080        if (oldMeta.getRelationship() != newMeta.getRelationship()) {
1081            evolver.addEvolveError
1082                (this, newFormat,
1083                 "Change detected in the relate attribute (Relationship) " +
1084                 "of a secondary key",
1085                 "Old key: " + oldMeta.getKeyName() +
1086                 " relate: " + oldMeta.getRelationship() +
1087                 " new key: " + newMeta.getKeyName() +
1088                 " relate: " + newMeta.getRelationship());
1089            return false;
1090        }
1091        return true;
1092    }
1093
1094    /**
1095     * Checks that the type of a key field did not change, as known from
1096     * metadata when a class conversion is used.
1097     */
1098    private boolean checkKeyTypeChange(Format newFormat,
1099                                       FieldMetadata oldMeta,
1100                                       FieldMetadata newMeta,
1101                                       String keyLabel,
1102                                       Evolver evolver) {
1103        String oldClass = oldMeta.getClassName();
1104        String newClass = newMeta.getClassName();
1105        if (!oldClass.equals(newClass)) {
1106            SimpleCatalog catalog = SimpleCatalog.getInstance();
1107            Format oldType = catalog.getFormat(oldClass);
1108            Format newType = catalog.getFormat(newClass);
1109            if (oldType == null || newType == null ||
1110                ((oldType.getWrapperFormat() == null ||
1111                  oldType.getWrapperFormat().getId() !=
1112                  newType.getId()) &&
1113                 (newType.getWrapperFormat() == null ||
1114                  newType.getWrapperFormat().getId() !=
1115                  oldType.getId()))) {
1116                evolver.addEvolveError
1117                    (this, newFormat,
1118                     "Type change detected for " + keyLabel,
1119                     "Old field type: " + oldClass +
1120                     " is not compatible with the new type: " +
1121                     newClass +
1122                     " old field: " + oldMeta.getName() +
1123                     " new field: " + newMeta.getName());
1124                return false;
1125            }
1126        }
1127        return true;
1128    }
1129
1130    /**
1131     * Special case for creating FieldReaders for a deleted class when it
1132     * appears in the class hierarchy of its non-deleted subclass.
1133     */
1134    private boolean evolveDeletedClass(Evolver evolver) {
1135        assert isDeleted();
1136        if (secKeyFieldReader == null || nonKeyFieldReader == null) {
1137            if (priKeyField != null &&
1138                getEntityFormat() != null &&
1139                !getEntityFormat().isDeleted()) {
1140                evolver.addEvolveError
1141                    (this, this,
1142                     "Class containing primary key field was deleted ",
1143                     "Primary key is needed in an entity class hierarchy: " +
1144                     priKeyField.getName());
1145                return false;
1146            } else {
1147                secKeyFieldReader = new SkipFieldReader(0, secKeyFields);
1148                nonKeyFieldReader = new SkipFieldReader(0, nonKeyFields);
1149                return true;
1150            }
1151        } else {
1152            return true;
1153        }
1154    }
1155
1156    /**
1157     * Creates a FieldReader for secondary key fields and non-key fields if
1158     * necessary.  Checks the primary key field if necessary.  Does not evolve
1159     * superclass format fields.
1160     */
1161    private int evolveAllFields(ComplexFormat newFormat, Evolver evolver) {
1162
1163        assert !isDeleted();
1164        secKeyFieldReader = null;
1165        nonKeyFieldReader = null;
1166        oldToNewKeyMap = null;
1167
1168        /* Evolve primary key field. */
1169        boolean evolveFailure = false;
1170        boolean evolveNeeded = false;
1171        if (priKeyField != null) {
1172            int result = evolver.evolveRequiredKeyField
1173                (this, newFormat, priKeyField, newFormat.priKeyField);
1174            if (result == Evolver.EVOLVE_FAILURE) {
1175                evolveFailure = true;
1176            } else if (result == Evolver.EVOLVE_NEEDED) {
1177                evolveNeeded = true;
1178            }
1179        }
1180
1181        /* Evolve secondary key fields. */
1182        FieldReader reader = evolveFieldList
1183            (secKeyFields, newFormat.secKeyFields, true,
1184             newFormat.nonKeyFields, newFormat, evolver);
1185        if (reader == FieldReader.EVOLVE_FAILURE) {
1186            evolveFailure = true;
1187        } else if (reader != null) {
1188            evolveNeeded = true;
1189        }
1190        if (reader != FieldReader.EVOLVE_NEEDED) {
1191            secKeyFieldReader = reader;
1192        }
1193
1194        /* Evolve non-key fields. */
1195        reader = evolveFieldList
1196            (nonKeyFields, newFormat.nonKeyFields, false,
1197             newFormat.secKeyFields, newFormat, evolver);
1198        if (reader == FieldReader.EVOLVE_FAILURE) {
1199            evolveFailure = true;
1200        } else if (reader != null) {
1201            evolveNeeded = true;
1202        }
1203        if (reader != FieldReader.EVOLVE_NEEDED) {
1204            nonKeyFieldReader = reader;
1205        }
1206
1207        /* Return result. */
1208        if (evolveFailure) {
1209            return Evolver.EVOLVE_FAILURE;
1210        } else if (evolveNeeded) {
1211            return Evolver.EVOLVE_NEEDED;
1212        } else {
1213            return Evolver.EVOLVE_NONE;
1214        }
1215    }
1216
1217    /**
1218     * Returns a FieldReader that reads no fields.
1219     *
1220     * Instead of adding a DoNothingFieldReader class, we use a
1221     * MultiFieldReader with an empty field list.  We do not add a new
1222     * FieldReader class to avoid changing the catalog format.  [#15524]
1223     */
1224    private FieldReader getDoNothingFieldReader() {
1225        List<FieldReader> emptyList = Collections.emptyList();
1226        return new MultiFieldReader(emptyList);
1227    }
1228
1229    /**
1230     * Evolves a list of fields, either secondary key or non-key fields, for a
1231     * single class format.
1232     *
1233     * @return a FieldReader if field evolution is needed, null if no evolution
1234     * is needed, or FieldReader.EVOLVE_FAILURE if an evolution error occurs.
1235     */
1236    private FieldReader evolveFieldList(List<FieldInfo> oldFields,
1237                                        List<FieldInfo> newFields,
1238                                        boolean isOldSecKeyField,
1239                                        List<FieldInfo> otherNewFields,
1240                                        ComplexFormat newFormat,
1241                                        Evolver evolver) {
1242        Mutations mutations = evolver.getMutations();
1243        boolean evolveFailure = false;
1244        boolean evolveNeeded = false;
1245        boolean readerNeeded = false;
1246        List<FieldReader> fieldReaders = new ArrayList<FieldReader>();
1247        FieldReader currentReader = null;
1248        int prevNewFieldIndex = newFields.size();
1249        int newFieldsMatched = 0;
1250
1251        /*
1252         * Add FieldReaders to the list in old field storage order, since that
1253         * is the order in which field values must be read.
1254         */
1255        fieldLoop:
1256        for (int oldFieldIndex = 0;
1257             oldFieldIndex < oldFields.size();
1258             oldFieldIndex += 1) {
1259
1260            FieldInfo oldField = oldFields.get(oldFieldIndex);
1261            String oldName = oldField.getName();
1262            SecondaryKeyMetadata oldMeta = null;
1263            if (isOldSecKeyField) {
1264                oldMeta = clsMeta.getSecondaryKeys().get(oldName);
1265                assert oldMeta != null;
1266            }
1267
1268            /* Get field mutations. */
1269            Renamer renamer = mutations.getRenamer
1270                (getClassName(), getVersion(), oldName);
1271            Deleter deleter = mutations.getDeleter
1272                (getClassName(), getVersion(), oldName);
1273            Converter converter = mutations.getConverter
1274                (getClassName(), getVersion(), oldName);
1275            if (deleter != null && (converter != null || renamer != null)) {
1276                evolver.addInvalidMutation
1277                    (this, newFormat, deleter,
1278                     "Field Deleter is not allowed along with a Renamer or " +
1279                     "Converter for the same field: " + oldName);
1280                evolveFailure = true;
1281                continue fieldLoop;
1282            }
1283
1284            /*
1285             * Match old and new field by name, taking into account the Renamer
1286             * mutation.  If the @SecondaryKey annotation was added or removed,
1287             * the field will have moved from one of the two field lists to the
1288             * other.
1289             */
1290            String newName = (renamer != null) ?
1291                renamer.getNewName() : oldName;
1292            if (!oldName.equals(newName)) {
1293                if (newToOldFieldMap == null) {
1294                    newToOldFieldMap = new HashMap<String,String>();
1295                }
1296                newToOldFieldMap.put(newName, oldName);
1297            }
1298            int newFieldIndex = FieldInfo.getFieldIndex(newFields, newName);
1299            FieldInfo newField = null;
1300            boolean isNewSecKeyField = isOldSecKeyField;
1301            if (newFieldIndex >= 0) {
1302                newField = newFields.get(newFieldIndex);
1303            } else {
1304                newFieldIndex = FieldInfo.getFieldIndex
1305                    (otherNewFields, newName);
1306                if (newFieldIndex >= 0) {
1307                    newField = otherNewFields.get(newFieldIndex);
1308                    isNewSecKeyField = !isOldSecKeyField;
1309                }
1310                evolveNeeded = true;
1311                readerNeeded = true;
1312            }
1313
1314            /* Apply field Deleter and continue. */
1315            if (deleter != null) {
1316                if (newField != null) {
1317                    evolver.addInvalidMutation
1318                        (this, newFormat, deleter,
1319                         "Field Deleter is not allowed when the persistent " +
1320                         "field is still present: " + oldName);
1321                    evolveFailure = true;
1322                }
1323                /* A SkipFieldReader can read multiple sequential fields. */
1324                if (currentReader instanceof SkipFieldReader &&
1325                    currentReader.acceptField
1326                        (oldFieldIndex, newFieldIndex, isNewSecKeyField)) {
1327                    currentReader.addField(oldField);
1328                } else {
1329                    currentReader = new SkipFieldReader
1330                        (oldFieldIndex, oldField);
1331                    fieldReaders.add(currentReader);
1332                    readerNeeded = true;
1333                    evolveNeeded = true;
1334                }
1335                if (isOldSecKeyField) {
1336                    if (oldToNewKeyMap == null) {
1337                        oldToNewKeyMap = new HashMap<String,String>();
1338                    }
1339                    oldToNewKeyMap.put(oldMeta.getKeyName(), null);
1340                }
1341                continue fieldLoop;
1342            } else {
1343                if (newField == null) {
1344                    evolver.addMissingMutation
1345                        (this, newFormat,
1346                         "Field is not present or not persistent: " +
1347                         oldName);
1348                    evolveFailure = true;
1349                    continue fieldLoop;
1350                }
1351            }
1352
1353            /*
1354             * The old field corresponds to a known new field, and no Deleter
1355             * mutation applies.
1356             */
1357            newFieldsMatched += 1;
1358
1359            /* Get and process secondary key metadata changes. */
1360            SecondaryKeyMetadata newMeta = null;
1361            if (isOldSecKeyField && isNewSecKeyField) {
1362                newMeta = newFormat.clsMeta.getSecondaryKeys().get(newName);
1363                assert newMeta != null;
1364
1365                /* Validate metadata changes. */
1366                if (!checkSecKeyMetadata
1367                        (newFormat, oldMeta, newMeta, evolver)) {
1368                    evolveFailure = true;
1369                    continue fieldLoop;
1370                }
1371
1372                /*
1373                 * Check for a renamed key and save the old-to-new mapping for
1374                 * use in renaming the secondary database and for key
1375                 * extraction.
1376                 */
1377                String oldKeyName = oldMeta.getKeyName();
1378                String newKeyName = newMeta.getKeyName();
1379                if (!oldKeyName.equals(newKeyName)) {
1380                    if (oldToNewKeyMap == null) {
1381                        oldToNewKeyMap = new HashMap<String,String>();
1382                    }
1383                    oldToNewKeyMap.put(oldName, newName);
1384                    evolveNeeded = true;
1385                }
1386            } else if (isOldSecKeyField && !isNewSecKeyField) {
1387                if (oldToNewKeyMap == null) {
1388                    oldToNewKeyMap = new HashMap<String,String>();
1389                }
1390                oldToNewKeyMap.put(oldMeta.getKeyName(), null);
1391            }
1392
1393            /* Apply field Converter and continue. */
1394            if (converter != null) {
1395                if (isOldSecKeyField) {
1396                    evolver.addInvalidMutation
1397                        (this, newFormat, converter,
1398                         "Field Converter is not allowed for secondary key " +
1399                         "fields: " + oldName);
1400                    evolveFailure = true;
1401                } else {
1402                    currentReader = new ConvertFieldReader
1403                        (converter, oldFieldIndex, newFieldIndex,
1404                         isNewSecKeyField);
1405                    fieldReaders.add(currentReader);
1406                    readerNeeded = true;
1407                    evolveNeeded = true;
1408                }
1409                continue fieldLoop;
1410            }
1411
1412            /*
1413             * Evolve the declared version of the field format and all versions
1414             * more recent, and the formats for all of their subclasses.  While
1415             * we're at it, check to see if all possible classes are converted.
1416             */
1417            boolean allClassesConverted = true;
1418            Format oldFieldFormat = oldField.getType();
1419            for (Format formatVersion = oldFieldFormat.getLatestVersion();
1420                 true;
1421                 formatVersion = formatVersion.getPreviousVersion()) {
1422                assert formatVersion != null;
1423                if (!evolver.evolveFormat(formatVersion)) {
1424                    evolveFailure = true;
1425                    continue fieldLoop;
1426                }
1427                if (!formatVersion.isNew() &&
1428                    !evolver.isClassConverted(formatVersion)) {
1429                    allClassesConverted = false;
1430                }
1431                Set<Format> subclassFormats =
1432                    evolver.getSubclassFormats(formatVersion);
1433                if (subclassFormats != null) {
1434                    for (Format format2 : subclassFormats) {
1435                        if (!evolver.evolveFormat(format2)) {
1436                            evolveFailure = true;
1437                            continue fieldLoop;
1438                        }
1439                        if (!format2.isNew() &&
1440                            !evolver.isClassConverted(format2)) {
1441                            allClassesConverted = false;
1442                        }
1443                    }
1444                }
1445                if (formatVersion == oldFieldFormat) {
1446                    break;
1447                }
1448            }
1449
1450            /*
1451             * Check for compatible field types and apply a field widener if
1452             * needed.  If no widener is needed, fall through and apply a
1453             * PlainFieldReader.
1454             */
1455            Format oldLatestFormat = oldFieldFormat.getLatestVersion();
1456            Format newFieldFormat = newField.getType();
1457            if (oldLatestFormat.getClassName().equals
1458                    (newFieldFormat.getClassName()) &&
1459                !oldLatestFormat.isDeleted()) {
1460                /* Formats are identical.  Fall through. */
1461            } else if (allClassesConverted) {
1462                /* All old classes will be converted.  Fall through. */
1463                evolveNeeded = true;
1464            } else if (WidenerInput.isWideningSupported
1465                        (oldLatestFormat, newFieldFormat, isOldSecKeyField)) {
1466                /* Apply field widener and continue. */
1467                currentReader = new WidenFieldReader
1468                    (oldLatestFormat, newFieldFormat, newFieldIndex,
1469                     isNewSecKeyField);
1470                fieldReaders.add(currentReader);
1471                readerNeeded = true;
1472                evolveNeeded = true;
1473                continue fieldLoop;
1474            } else {
1475                boolean refWidened = false;
1476                if (!newFieldFormat.isPrimitive() &&
1477                    !oldLatestFormat.isPrimitive() &&
1478                    !oldLatestFormat.isDeleted() &&
1479                    !evolver.isClassConverted(oldLatestFormat)) {
1480                    Class oldCls = oldLatestFormat.getExistingType();
1481                    Class newCls = newFieldFormat.getExistingType();
1482                    if (newCls.isAssignableFrom(oldCls)) {
1483                        refWidened = true;
1484                    }
1485                }
1486                if (refWidened) {
1487                    /* A reference type has been widened.  Fall through. */
1488                    evolveNeeded = true;
1489                } else {
1490                    /* Types are not compatible. */
1491                    evolver.addMissingMutation
1492                        (this, newFormat,
1493                         "Old field type: " + oldLatestFormat.getClassName() +
1494                         " is not compatible with the new type: " +
1495                         newFieldFormat.getClassName() +
1496                         " for field: " + oldName);
1497                    evolveFailure = true;
1498                    continue fieldLoop;
1499                }
1500            }
1501
1502            /*
1503             * Old to new field conversion is not needed or is automatic.  Read
1504             * fields as if no evolution is needed.  A PlainFieldReader can
1505             * read multiple sequential fields.
1506             */
1507            if (currentReader instanceof PlainFieldReader &&
1508                currentReader.acceptField
1509                    (oldFieldIndex, newFieldIndex, isNewSecKeyField)) {
1510                currentReader.addField(oldField);
1511            } else {
1512                currentReader = new PlainFieldReader
1513                    (oldFieldIndex, newFieldIndex, isNewSecKeyField);
1514                fieldReaders.add(currentReader);
1515            }
1516        }
1517
1518        /*
1519         * If there are new fields, then the old fields must be read using a
1520         * reader, even if the old field list is empty.  Using the accessor
1521         * directly will read fields in the wrong order and will read fields
1522         * that were moved between lists (when adding and dropping
1523         * @SecondaryKey).  [#15524]
1524         */
1525        if (newFieldsMatched < newFields.size()) {
1526            evolveNeeded = true;
1527            readerNeeded = true;
1528        }
1529
1530        if (evolveFailure) {
1531            return FieldReader.EVOLVE_FAILURE;
1532        } else if (readerNeeded) {
1533            if (fieldReaders.size() == 0) {
1534                return getDoNothingFieldReader();
1535            } else if (fieldReaders.size() == 1) {
1536                return fieldReaders.get(0);
1537            } else {
1538                return new MultiFieldReader(fieldReaders);
1539            }
1540        } else if (evolveNeeded) {
1541            return FieldReader.EVOLVE_NEEDED;
1542        } else {
1543            return null;
1544        }
1545    }
1546
1547    /**
1548     * Base class for all FieldReader subclasses.  A FieldReader reads one or
1549     * more fields in the old format data, and may call the new format Accessor
1550     * to set the field values.
1551     */
1552    private static abstract class FieldReader implements Serializable {
1553
1554        static final FieldReader EVOLVE_NEEDED =
1555            new PlainFieldReader(0, 0, false);
1556        static final FieldReader EVOLVE_FAILURE =
1557            new PlainFieldReader(0, 0, false);
1558
1559        private static final long serialVersionUID = 866041475399255164L;
1560
1561        FieldReader() {
1562        }
1563
1564        void initialize(Catalog catalog,
1565                        int initVersion,
1566                        ComplexFormat oldParentFormat,
1567                        ComplexFormat newParentFormat,
1568                        boolean isOldSecKey) {
1569        }
1570
1571        boolean acceptField(int oldFieldIndex,
1572                            int newFieldIndex,
1573                            boolean isNewSecKeyField) {
1574            return false;
1575        }
1576
1577        void addField(FieldInfo oldField) {
1578            throw new UnsupportedOperationException();
1579        }
1580
1581        abstract void readFields(Object o,
1582                                 EntityInput input,
1583                                 Accessor accessor,
1584                                 int superLevel);
1585    }
1586
1587    /**
1588     * Reads a continguous block of fields that have the same format in the old
1589     * and new formats.
1590     */
1591    private static class PlainFieldReader extends FieldReader {
1592
1593        private static final long serialVersionUID = 1795593463439931402L;
1594
1595        private int startField;
1596        private int endField;
1597        private boolean secKeyField;
1598        private transient int endOldField;
1599
1600        PlainFieldReader(int oldFieldIndex,
1601                         int newFieldIndex,
1602                         boolean isNewSecKeyField) {
1603            endOldField = oldFieldIndex;
1604            startField = newFieldIndex;
1605            endField = newFieldIndex;
1606            secKeyField = isNewSecKeyField;
1607        }
1608
1609        @Override
1610        boolean acceptField(int oldFieldIndex,
1611                            int newFieldIndex,
1612                            boolean isNewSecKeyField) {
1613            return oldFieldIndex == endOldField + 1 &&
1614                   newFieldIndex == endField + 1 &&
1615                   secKeyField == isNewSecKeyField;
1616        }
1617
1618        @Override
1619        void addField(FieldInfo oldField) {
1620            endField += 1;
1621            endOldField += 1;
1622        }
1623
1624        @Override
1625        final void readFields(Object o,
1626                              EntityInput input,
1627                              Accessor accessor,
1628                              int superLevel) {
1629            if (secKeyField) {
1630                accessor.readSecKeyFields
1631                    (o, input, startField, endField, superLevel);
1632            } else {
1633                accessor.readNonKeyFields
1634                    (o, input, startField, endField, superLevel);
1635            }
1636        }
1637    }
1638
1639    /**
1640     * Skips a continguous block of fields that exist in the old format but not
1641     * in the new format.
1642     */
1643    private static class SkipFieldReader extends FieldReader {
1644
1645        private static final long serialVersionUID = -3060281692155253098L;
1646
1647        private List<Format> fieldFormats;
1648        private transient int endField;
1649
1650        SkipFieldReader(int startField, List<FieldInfo> fields) {
1651            endField = startField + fields.size() - 1;
1652            fieldFormats = new ArrayList<Format>(fields.size());
1653            for (FieldInfo field : fields) {
1654                fieldFormats.add(field.getType());
1655            }
1656        }
1657
1658        SkipFieldReader(int startField, FieldInfo oldField) {
1659            endField = startField;
1660            fieldFormats = new ArrayList<Format>();
1661            fieldFormats.add(oldField.getType());
1662        }
1663
1664        @Override
1665        boolean acceptField(int oldFieldIndex,
1666                            int newFieldIndex,
1667                            boolean isNewSecKeyField) {
1668            return oldFieldIndex == endField + 1;
1669        }
1670
1671        @Override
1672        void addField(FieldInfo oldField) {
1673            endField += 1;
1674            fieldFormats.add(oldField.getType());
1675        }
1676
1677        @Override
1678        final void readFields(Object o,
1679                              EntityInput input,
1680                              Accessor accessor,
1681                              int superLevel) {
1682            for (Format format : fieldFormats) {
1683                input.skipField(format);
1684            }
1685        }
1686    }
1687
1688    /**
1689     * Converts a single field using a field Converter.
1690     */
1691    private static class ConvertFieldReader extends FieldReader {
1692
1693        private static final long serialVersionUID = 8736410481633998710L;
1694
1695        private Converter converter;
1696        private int oldFieldNum;
1697        private int fieldNum;
1698        private boolean secKeyField;
1699        private transient Format oldFormat;
1700        private transient Format newFormat;
1701
1702        ConvertFieldReader(Converter converter,
1703                           int oldFieldIndex,
1704                           int newFieldIndex,
1705                           boolean isNewSecKeyField) {
1706            this.converter = converter;
1707            oldFieldNum = oldFieldIndex;
1708            fieldNum = newFieldIndex;
1709            secKeyField = isNewSecKeyField;
1710        }
1711
1712        @Override
1713        void initialize(Catalog catalog,
1714                        int initVersion,
1715                        ComplexFormat oldParentFormat,
1716                        ComplexFormat newParentFormat,
1717                        boolean isOldSecKey) {
1718
1719            /*
1720             * The oldFieldNum field was added as part of a bug fix.  If not
1721             * present in this version of the catalog, we assume it is equal to
1722             * the new field index.  The code prior to the bug fix assumes the
1723             * old and new fields have the same index. [#15797]
1724             */
1725            if (initVersion < 1) {
1726                oldFieldNum = fieldNum;
1727            }
1728
1729            if (isOldSecKey) {
1730                oldFormat =
1731                    oldParentFormat.secKeyFields.get(oldFieldNum).getType();
1732            } else {
1733                oldFormat =
1734                    oldParentFormat.nonKeyFields.get(oldFieldNum).getType();
1735            }
1736            if (secKeyField) {
1737                newFormat =
1738                    newParentFormat.secKeyFields.get(fieldNum).getType();
1739            } else {
1740                newFormat =
1741                    newParentFormat.nonKeyFields.get(fieldNum).getType();
1742            }
1743        }
1744
1745        @Override
1746        final void readFields(Object o,
1747                              EntityInput input,
1748                              Accessor accessor,
1749                              int superLevel) {
1750
1751            /* Create and read the old format instance in raw mode. */
1752            boolean currentRawMode = input.setRawAccess(true);
1753            Object value;
1754            try {
1755                if (oldFormat.isPrimitive()) {
1756                    value = input.readKeyObject(oldFormat);
1757                } else {
1758                    value = input.readObject();
1759                }
1760            } finally {
1761                input.setRawAccess(currentRawMode);
1762            }
1763
1764            /* Convert the raw instance to the current format. */
1765            Catalog catalog = input.getCatalog();
1766            value = converter.getConversion().convert(value);
1767
1768            /* Use a RawSingleInput to convert and type-check the value. */
1769            EntityInput rawInput = new RawSingleInput
1770                (catalog, currentRawMode, null, value, newFormat);
1771
1772            if (secKeyField) {
1773                accessor.readSecKeyFields
1774                    (o, rawInput, fieldNum, fieldNum, superLevel);
1775            } else {
1776                accessor.readNonKeyFields
1777                    (o, rawInput, fieldNum, fieldNum, superLevel);
1778            }
1779        }
1780    }
1781
1782    /**
1783     * Widens a single field using a field Converter.
1784     */
1785    private static class WidenFieldReader extends FieldReader {
1786
1787        private static final long serialVersionUID = -2054520670170407282L;
1788
1789        private int fromFormatId;
1790        private int toFormatId;
1791        private int fieldNum;
1792        private boolean secKeyField;
1793
1794        WidenFieldReader(Format oldFormat,
1795                         Format newFormat,
1796                         int newFieldIndex,
1797                         boolean isNewSecKeyField) {
1798            fromFormatId = oldFormat.getId();
1799            toFormatId = newFormat.getId();
1800            fieldNum = newFieldIndex;
1801            secKeyField = isNewSecKeyField;
1802        }
1803
1804        @Override
1805        final void readFields(Object o,
1806                              EntityInput input,
1807                              Accessor accessor,
1808                              int superLevel) {
1809
1810            /* The Accessor reads the field value from a WidenerInput. */
1811            EntityInput widenerInput = new WidenerInput
1812                (input, fromFormatId, toFormatId);
1813
1814            if (secKeyField) {
1815                accessor.readSecKeyFields
1816                    (o, widenerInput, fieldNum, fieldNum, superLevel);
1817            } else {
1818                accessor.readNonKeyFields
1819                    (o, widenerInput, fieldNum, fieldNum, superLevel);
1820            }
1821        }
1822    }
1823
1824    /**
1825     * A FieldReader composed of other FieldReaders, and that calls them in
1826     * sequence.  Used when more than one FieldReader is needed for a list of
1827     * fields.
1828     */
1829    private static class MultiFieldReader extends FieldReader {
1830
1831        private static final long serialVersionUID = -6035976787562441473L;
1832
1833        private List<FieldReader> subReaders;
1834
1835        MultiFieldReader(List<FieldReader> subReaders) {
1836            this.subReaders = subReaders;
1837        }
1838
1839        @Override
1840        void initialize(Catalog catalog,
1841                        int initVersion,
1842                        ComplexFormat oldParentFormat,
1843                        ComplexFormat newParentFormat,
1844                        boolean isOldSecKey) {
1845            for (FieldReader reader : subReaders) {
1846                reader.initialize
1847                    (catalog, initVersion, oldParentFormat, newParentFormat,
1848                     isOldSecKey);
1849            }
1850        }
1851
1852        @Override
1853        final void readFields(Object o,
1854                              EntityInput input,
1855                              Accessor accessor,
1856                              int superLevel) {
1857            for (FieldReader reader : subReaders) {
1858                reader.readFields(o, input, accessor, superLevel);
1859            }
1860        }
1861    }
1862
1863    /**
1864     * The Reader for evolving ComplexFormat instances.  Reads the old format
1865     * data one class (one level in the class hierarchy) at a time.  If an
1866     * Accessor is used at a given level, the Accessor is used for the
1867     * corresponding level in the new class hierarchy (classes may be
1868     * inserted/deleted during evolution).  At each level, a FieldReader is
1869     * called to evolve the secondary key and non-key lists of fields.
1870     */
1871    private static class EvolveReader implements Reader {
1872
1873        static final int DO_NOT_READ_ACCESSOR = Integer.MAX_VALUE;
1874
1875        private static final long serialVersionUID = -1016140948306913283L;
1876
1877        private transient ComplexFormat newFormat;
1878
1879        /**
1880         * oldHierarchy contains the formats of the old class hierarchy in most
1881         * to least derived class order.
1882         */
1883        private transient ComplexFormat[] oldHierarchy;
1884
1885        /**
1886         * newHierarchyLevels contains the corresponding level in the new
1887         * hierarchy for each format in oldHierarchy. newHierarchyLevels is
1888         * indexed by the oldHierarchy index.
1889         */
1890        private int[] newHierarchyLevels;
1891
1892        EvolveReader(List<Integer> newHierarchyLevelsList) {
1893            int oldDepth = newHierarchyLevelsList.size();
1894            newHierarchyLevels = new int[oldDepth];
1895            newHierarchyLevelsList.toArray();
1896            for (int i = 0; i < oldDepth; i += 1) {
1897                newHierarchyLevels[i] = newHierarchyLevelsList.get(i);
1898            }
1899        }
1900
1901        public void initializeReader(Catalog catalog,
1902                                     int initVersion,
1903                                     Format oldFormatParam) {
1904
1905            ComplexFormat oldFormat = (ComplexFormat) oldFormatParam;
1906            newFormat = oldFormat.getComplexLatest();
1907            newFormat.initializeIfNeeded(catalog);
1908
1909            /* Create newHierarchy array. */
1910            int newDepth = 0;
1911            for (Format format = newFormat;
1912                 format != null;
1913                 format = format.getSuperFormat()) {
1914                newDepth += 1;
1915            }
1916            ComplexFormat[] newHierarchy = new ComplexFormat[newDepth];
1917            int level = 0;
1918            for (ComplexFormat format = newFormat;
1919                 format != null;
1920                 format = format.getComplexSuper()) {
1921                newHierarchy[level] = format;
1922                level += 1;
1923            }
1924            assert level == newDepth;
1925
1926            /* Create oldHierarchy array and initialize FieldReaders. */
1927            int oldDepth = newHierarchyLevels.length;
1928            oldHierarchy = new ComplexFormat[oldDepth];
1929            level = 0;
1930            for (ComplexFormat oldFormat2 = oldFormat;
1931                 oldFormat2 != null;
1932                 oldFormat2 = oldFormat2.getComplexSuper()) {
1933                oldHierarchy[level] = oldFormat2;
1934                int level2 = newHierarchyLevels[level];
1935                ComplexFormat newFormat2 = (level2 != DO_NOT_READ_ACCESSOR) ?
1936                    newHierarchy[level2] : null;
1937                level += 1;
1938                if (oldFormat2.secKeyFieldReader != null) {
1939                    oldFormat2.secKeyFieldReader.initialize
1940                        (catalog, initVersion, oldFormat2, newFormat2, true);
1941                }
1942                if (oldFormat2.nonKeyFieldReader != null) {
1943                    oldFormat2.nonKeyFieldReader.initialize
1944                        (catalog, initVersion, oldFormat2, newFormat2, false);
1945                }
1946            }
1947            assert level == oldDepth;
1948        }
1949
1950        public Object newInstance(EntityInput input, boolean rawAccess) {
1951            return newFormat.newInstance(input, rawAccess);
1952        }
1953
1954        public void readPriKey(Object o,
1955                               EntityInput input,
1956                               boolean rawAccess) {
1957            /* No conversion necessary for primary keys. */
1958            newFormat.readPriKey(o, input, rawAccess);
1959        }
1960
1961        public Object readObject(Object o,
1962                                 EntityInput input,
1963                                 boolean rawAccess) {
1964
1965            /* Use the Accessor for the new format. */
1966            Accessor accessor = rawAccess ? newFormat.rawAccessor
1967                                          : newFormat.objAccessor;
1968
1969            /* Read old format fields from the top-most class downward. */
1970            int maxMinusOne = oldHierarchy.length - 1;
1971
1972            /* Read secondary key fields with the adjusted superclass level. */
1973            for (int i = maxMinusOne; i >= 0; i -= 1) {
1974                FieldReader reader = oldHierarchy[i].secKeyFieldReader;
1975                int newLevel = newHierarchyLevels[i];
1976                if (reader != null) {
1977                    reader.readFields(o, input, accessor, newLevel);
1978                } else if (newLevel != DO_NOT_READ_ACCESSOR) {
1979                    accessor.readSecKeyFields
1980                        (o, input, 0, Accessor.MAX_FIELD_NUM, newLevel);
1981                }
1982            }
1983
1984            /* Read non-key fields with the adjusted superclass level. */
1985            for (int i = maxMinusOne; i >= 0; i -= 1) {
1986                FieldReader reader = oldHierarchy[i].nonKeyFieldReader;
1987                int newLevel = newHierarchyLevels[i];
1988                if (reader != null) {
1989                    reader.readFields(o, input, accessor, newLevel);
1990                } else if (newLevel != DO_NOT_READ_ACCESSOR) {
1991                    accessor.readNonKeyFields
1992                        (o, input, 0, Accessor.MAX_FIELD_NUM, newLevel);
1993                }
1994            }
1995            return o;
1996        }
1997    }
1998}
1999