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