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