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