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