com.sleepycat.persist.impl.Format Maven / Gradle / Ivy
The newest version!
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.persist.impl;
import java.io.Serializable;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.persist.evolve.Converter;
import com.sleepycat.persist.model.ClassMetadata;
import com.sleepycat.persist.model.EntityMetadata;
import com.sleepycat.persist.model.EntityModel;
import com.sleepycat.persist.model.FieldMetadata;
import com.sleepycat.persist.model.PrimaryKeyMetadata;
import com.sleepycat.persist.model.SecondaryKeyMetadata;
import com.sleepycat.persist.raw.RawField;
import com.sleepycat.persist.raw.RawObject;
import com.sleepycat.persist.raw.RawType;
/**
* The base class for all object formats. Formats are used to define the
* stored layout for all persistent classes, including simple types.
*
* The design documentation below describes the storage format for entities and
* its relationship to information stored per format in the catalog.
*
* Requirements
* ------------
* + Provides EntityBinding for objects and EntryBinding for keys.
* + Provides SecondaryKeyCreator, SecondaryMultiKeyCreator and
* SecondaryMultiKeyNullifier (SecondaryKeyNullifier is redundant).
* + Works with reflection and bytecode enhancement.
* + For reflection only, works with any entity model not just annotations.
* + Bindings are usable independently of the persist API.
* + Performance is almost equivalent to hand coded tuple bindings.
* + Small performance penalty for compatible class changes (new fields,
* widening).
* + Secondary key create/nullify do not have to deserialize the entire record;
* in other words, store secondary keys at the start of the data.
*
* Class Format
* ------------
* Every distinct class format is given a unique format ID. Class IDs are not
* equivalent to class version numbers (as in the version property of @Entity
* and @Persistent) because the format can change when the version number does
* not. Changes that cause a unique format ID to be assigned are:
*
* + Add field.
* + Widen field type.
* + Change primitive type to primitive wrapper class.
* + Add or drop secondary key.
* + Any incompatible class change.
*
* The last item, incompatible class changes, also correspond to a class
* version change.
*
* For each distinct class format the following information is conceptually
* stored in the catalog, keyed by format ID.
*
* - Class name
* - Class version number
* - Superclass format
* - Kind: simple, enum, complex, array
* - For kind == simple:
* - Primitive class
* - For kind == enum:
* - Array of constant names, sorted by name.
* - For kind == complex:
* - Primary key fieldInfo, or null if no primary key is declared
* - Array of secondary key fieldInfo, sorted by field name
* - Array of other fieldInfo, sorted by field name
* - For kind == array:
* - Component class format
* - Number of array dimensions
* - Other metadata for RawType
*
* Where fieldInfo is:
* - Field name
* - Field class
* - Other metadata for RawField
*
* Data Layout
* -----------
* For each entity instance the data layout is as follows:
*
* instanceData: formatId keyFields... nonKeyFields...
* keyFields: fieldValue...
* nonKeyFields: fieldValue...
*
* The formatId is the (positive non-zero) ID of a class format, defined above.
* This is ID of the most derived class of the instance. It is stored as a
* packed integer.
*
* Following the format ID, zero or more sets of secondary key field values
* appear, followed by zero or more sets of other class field values.
*
* The keyFields are the sets of secondary key fields for each class in order
* of the highest superclass first. Within a class, fields are ordered by
* field name.
*
* The nonKeyFields are the sets of other non-key fields for each class in
* order of the highest superclass first. Within a class, fields are ordered
* by field name.
*
* A field value is:
*
* fieldValue: primitiveValue
* | nullId
* | instanceRef
* | instanceData
* | simpleValue
* | enumValue
* | arrayValue
*
* For a primitive type, a primitive value is used as defined for tuple
* bindings. For float and double, sorted float and sorted double tuple values
* are used.
*
* For a non-primitive type with a null value, a nullId is used that has a zero
* (illegal formatId) value. This includes String and other simple reference
* types. The formatId is stored as a packed integer, meaning that it is
* stored as a single zero byte.
*
* For a non-primitive type, an instanceRef is used for a non-null instance
* that appears earlier in the data byte array. An instanceRef is the negation
* of the byte offset of the instanceData that appears earlier. It is stored
* as a packed integer.
*
* The remaining rules apply only to reference types with non-null values that
* do not appear earlier in the data array.
*
* For an array type, an array formatId is used that identifies the component
* type and the number of array dimensions. This is followed by an array
* length (stored as a packed integer) and zero or more fieldValue elements.
* For an array with N+1 dimensions where N is greater than zero, the leftmost
* dimension is enumerated such that each fieldValue element is itself an array
* of N dimensions or null.
*
* arrayValue: formatId length fieldValue...
*
* For an enum type, an enumValue is used, consisting of a formatId that
* identifies the enum class and an enumIndex (stored as a packed integer) that
* identifies the constant name in the enum constant array of the enum class
* format:
*
* enumValue: formatId enumIndex
*
* For a simple type, a simpleValue is used. This consists of the formatId
* that identifies the class followed by the simple type value. For a
* primitive wrapper type the simple type value is the corresponding primitive,
* for a Date it is the milliseconds as a long primitive, and for BigInteger or
* BigDecimal it is a byte array as defined for tuple bindings of these types.
*
* simpleValue: formatId value
*
* For all other complex types, an instanceData is used, which is defined
* above.
*
* Secondary Keys
* --------------
* For secondary key support we must account for writing and nullifying
* specific keys. Rather than instantiating the entity and then performing
* the secondary key operation, we strive to perform the secondary key
* operation directly on the byte format.
*
* To create a secondary key we skip over other fields and then copy the bytes
* of the embedded key. This approach is very efficient because a) the entity
* is not instantiated, and b) the secondary keys are stored at the beginning
* of the byte format and can be quickly read.
*
* To nullify we currently instantiate the raw entity, set the key field to null
* (or remove it from the array/collection), and convert the raw entity back to
* bytes. Although the performance of this approach is not ideal because it
* requires serialization, it avoids the complexity of modifying the packed
* serialized format directly, adjusting references to key objects, etc. Plus,
* when we nullify a key we are going to write the record, so the serialization
* overhead may not be significant. For the record, I tried implementing
* nullification of the bytes directly and found it was much too complex.
*
* Lifecycle
* ---------
* Format are managed by a Catalog class. Simple formats are managed by
* SimpleCatalog, and are copied from the SimpleCatalog by PersistCatalog.
* Other formats are managed by PersistCatalog. The lifecycle of a format
* instance is:
*
* - Constructed by the catalog when a format is requested for a Class
* that currently has no associated format.
*
* - The catalog calls setId() and adds the format to its format list
* (indexed by format id) and map (keyed by class name).
*
* - The catalog calls collectRelatedFormats(), where a format can create
* additional formats that it needs, or that should also be persistent.
*
* - The catalog calls initializeIfNeeded(), which calls the initialize()
* method of the format class.
*
* - initialize() should initialize any transient fields in the format.
* initialize() can assume that all related formats are available in the
* catalog. It may call initializeIfNeeded() for those related formats, if
* it needs to interact with an initialized related format; this does not
* cause a cycle, because initializeIfNeeded() does nothing for an already
* initialized format.
*
* - The catalog creates a group of related formats at one time, and then
* writes its entire list of formats to the catalog DB as a single record.
* This grouping reduces the number of writes.
*
* - When a catalog is opened and the list of existing formats is read. After
* a format is deserialized, its initializeIfNeeded() method is called.
* setId() and collectRelatedFormats() are not called, since the ID and
* related formats are stored in serialized fields.
*
* - There are two modes for opening an existing catalog: raw mode and normal
* mode. In raw mode, the old format is used regardless of whether it
* matches the current class definition; in fact the class is not accessed
* and does not need to be present.
*
* - In normal mode, for each existing format that is initialized, a new format
* is also created based on the current class and metadata definition. If
* the two formats are equal, the new format is discarded. If they are
* unequal, the new format becomes the current format and the old format's
* evolve() method is called. evolve() is responsible for adjusting the
* old format for class evolution. Any number of non-current formats may
* exist for a given class, and are setup to evolve the single current format
* for the class.
*
* @author Mark Hayes
*/
public abstract class Format implements Reader, RawType, Serializable {
private static final long serialVersionUID = 545633644568489850L;
/** Null reference. */
static final int ID_NULL = 0;
/** Object */
static final int ID_OBJECT = 1;
/** Boolean */
static final int ID_BOOL = 2;
static final int ID_BOOL_W = 3;
/** Byte */
static final int ID_BYTE = 4;
static final int ID_BYTE_W = 5;
/** Short */
static final int ID_SHORT = 6;
static final int ID_SHORT_W = 7;
/** Integer */
static final int ID_INT = 8;
static final int ID_INT_W = 9;
/** Long */
static final int ID_LONG = 10;
static final int ID_LONG_W = 11;
/** Float */
static final int ID_FLOAT = 12;
static final int ID_FLOAT_W = 13;
/** Double */
static final int ID_DOUBLE = 14;
static final int ID_DOUBLE_W = 15;
/** Character */
static final int ID_CHAR = 16;
static final int ID_CHAR_W = 17;
/** String */
static final int ID_STRING = 18;
/** BigInteger */
static final int ID_BIGINT = 19;
/** BigDecimal */
static final int ID_BIGDEC = 20;
/** Date */
static final int ID_DATE = 21;
/** Number */
static final int ID_NUMBER = 22;
/** First simple type. */
static final int ID_SIMPLE_MIN = 2;
/** Last simple type. */
static final int ID_SIMPLE_MAX = 21;
/** Last predefined ID, after which dynamic IDs are assigned. */
static final int ID_PREDEFINED = 30;
static boolean isPredefined(Format format) {
return format.getId() <= ID_PREDEFINED;
}
private int id;
private String className;
private Reader reader;
private Format superFormat;
private Format latestFormat;
private Format previousFormat;
private Set supertypes;
private boolean deleted;
private boolean unused;
private transient Catalog catalog;
private transient Class type;
private transient Format proxiedFormat;
private transient boolean initialized;
/**
* Creates a new format for a given class.
*/
Format(final Catalog catalog, final Class type) {
this(catalog, type.getName());
this.type = type;
addSupertypes();
}
/**
* Creates a format for class evolution when no class may be present.
*/
Format(final Catalog catalog, final String className) {
assert catalog != null;
assert className != null;
this.catalog = catalog;
this.className = className;
latestFormat = this;
supertypes = new HashSet();
}
/**
* Special handling for JE 3.0.12 beta formats.
*/
void migrateFromBeta(Map formatMap) {
if (latestFormat == null) {
latestFormat = this;
}
}
/**
* Initialize transient catalog field after deserialization. This must
* occur before any other usage.
*/
void initCatalog(final Catalog catalog) {
assert catalog != null;
this.catalog = catalog;
}
final boolean isNew() {
return id == 0;
}
final Catalog getCatalog() {
return catalog;
}
/**
* Returns the format ID.
*/
public final int getId() {
return id;
}
/**
* Called by the Catalog to set the format ID when a new format is added to
* the format list, before calling initializeIfNeeded().
*/
final void setId(int id) {
this.id = id;
}
/**
* Returns the class that this format represents. This method will return
* null in rawAccess mode, or for an unevolved format.
*/
final Class getType() {
return type;
}
/**
* Called to get the type when it is known to exist for an uninitialized
* format.
*/
final Class getExistingType() {
assert catalog != null;
if (type == null) {
try {
type = catalog.resolveClass(className);
} catch (ClassNotFoundException e) {
throw DbCompat.unexpectedException(e);
}
}
return type;
}
/**
* Returns the object for reading objects of the latest format. For the
* latest version format, 'this' is returned. For prior version formats, a
* reader that converts this version to the latest version is returned.
*/
final Reader getReader() {
/*
* For unit testing, record whether any un-evolved formats are
* encountered.
*/
if (this != reader) {
PersistCatalog.unevolvedFormatsEncountered = true;
}
return reader;
}
/**
* Changes the reader during format evolution.
*/
final void setReader(Reader reader) {
this.reader = reader;
}
/**
* Returns the format of the superclass.
*/
final Format getSuperFormat() {
return superFormat;
}
/**
* Called to set the format of the superclass during initialize().
*/
final void setSuperFormat(Format superFormat) {
this.superFormat = superFormat;
}
/**
* Returns the format that is proxied by this format. If non-null is
* returned, then this format is a PersistentProxy.
*/
final Format getProxiedFormat() {
return proxiedFormat;
}
/**
* Called by ProxiedFormat to set the proxied format.
*/
final void setProxiedFormat(Format proxiedFormat) {
this.proxiedFormat = proxiedFormat;
}
/**
* If this is the latest/evolved format, returns this; otherwise, returns
* the current version of this format. Note that this WILL return a
* format for a deleted class if the latest format happens to be deleted.
*/
final Format getLatestVersion() {
return latestFormat;
}
/**
* Returns the previous version of this format in the linked list of
* versions, or null if this is the only version.
*/
public final Format getPreviousVersion() {
return previousFormat;
}
/**
* Called by Evolver to set the latest format when this old format is
* evolved.
*/
final void setLatestVersion(Format newFormat) {
/*
* If this old format is the former latest version, link it to the new
* latest version. This creates a singly linked list of versions
* starting with the latest.
*/
if (latestFormat == this) {
newFormat.previousFormat = this;
}
latestFormat = newFormat;
}
/**
* Returns whether the class for this format was deleted.
*/
public final boolean isDeleted() {
return deleted;
}
/**
* Called by the Evolver when applying a Deleter mutation.
*/
final void setDeleted(boolean deleted) {
this.deleted = deleted;
}
/**
* Called by the Evolver for a format that is never referenced.
*/
final void setUnused(boolean unused) {
this.unused = unused;
}
/**
* Called by the Evolver with true when an entity format or any of its
* nested format were changed. Called by Store.evolve when an entity has
* been fully converted. Overridden by ComplexFormat.
*/
void setEvolveNeeded(boolean needed) {
throw DbCompat.unexpectedState();
}
/**
* Overridden by ComplexFormat.
*/
boolean getEvolveNeeded() {
throw DbCompat.unexpectedState();
}
/**
* For an entity format, returns whether the entity was written using the
* new String format. For a non-entity format, this method should not be
* called.
*
* Overridden by ComplexFormat.
*/
boolean getNewStringFormat() {
throw DbCompat.unexpectedState();
}
final boolean isInitialized() {
return initialized;
}
/**
* Called by the Catalog to initialize a format, and may also be called
* during initialize() for a related format to ensure that the related
* format is initialized. This latter case is allowed to support
* bidirectional dependencies. This method will do nothing if the format
* is already intialized.
*/
final void initializeIfNeeded(Catalog catalog, EntityModel model) {
assert catalog != null;
if (!initialized) {
initialized = true;
this.catalog = catalog;
/* Initialize objects serialized by an older Format class. */
if (latestFormat == null) {
latestFormat = this;
}
if (reader == null) {
reader = this;
}
/*
* The class is only guaranteed to be available in live (not raw)
* mode, for the current version of the format.
*/
if (type == null &&
isCurrentVersion() &&
(isSimple() || !catalog.isRawAccess())) {
getExistingType();
}
/* Perform subclass-specific initialization. */
initialize(catalog, model,
catalog.getInitVersion(this, false /*forReader*/));
reader.initializeReader
(catalog, model,
catalog.getInitVersion(this, true /*forReader*/),
this);
}
}
/**
* Called to initialize a separate Reader implementation. This method is
* called when no separate Reader exists, and does nothing.
*/
public void initializeReader(Catalog catalog,
EntityModel model,
int initVersion,
Format oldFormat) {
}
/**
* Adds all interfaces and superclasses to the supertypes set.
*/
private void addSupertypes() {
addInterfaces(type);
Class stype = type.getSuperclass();
while (stype != null && stype != Object.class) {
supertypes.add(stype.getName());
addInterfaces(stype);
stype = stype.getSuperclass();
}
}
/**
* Recursively adds interfaces to the supertypes set.
*/
private void addInterfaces(Class cls) {
Class[] interfaces = cls.getInterfaces();
for (Class iface : interfaces) {
if (iface != Enhanced.class) {
supertypes.add(iface.getName());
addInterfaces(iface);
}
}
}
/**
* Certain formats (ProxiedFormat for example) prohibit nested fields that
* reference the parent object. [#15815]
*/
boolean areNestedRefsProhibited() {
return false;
}
/* -- Start of RawType interface methods. -- */
public String getClassName() {
return className;
}
public int getVersion() {
ClassMetadata meta = getClassMetadata();
if (meta != null) {
return meta.getVersion();
} else {
return 0;
}
}
public Format getSuperType() {
return superFormat;
}
/* -- RawType methods that are overridden as needed in subclasses. -- */
public boolean isSimple() {
return false;
}
public boolean isPrimitive() {
return false;
}
public boolean isEnum() {
return false;
}
public List getEnumConstants() {
return null;
}
public boolean isArray() {
return false;
}
public int getDimensions() {
return 0;
}
public Format getComponentType() {
return null;
}
public Map getFields() {
return null;
}
public ClassMetadata getClassMetadata() {
return null;
}
public EntityMetadata getEntityMetadata() {
return null;
}
/* -- End of RawType methods. -- */
/* -- Methods that may optionally be overridden by subclasses. -- */
/**
* Called by EntityOutput in rawAccess mode to determine whether an object
* type is allowed to be assigned to a given field type.
*/
boolean isAssignableTo(Format format) {
if (proxiedFormat != null) {
return proxiedFormat.isAssignableTo(format);
} else {
return format == this ||
format.id == ID_OBJECT ||
supertypes.contains(format.className);
}
}
/**
* For primitive types only, returns their associated wrapper type.
*/
Format getWrapperFormat() {
return null;
}
/**
* Returns whether this format class is an entity class.
*/
boolean isEntity() {
return false;
}
/**
* Returns whether this class is present in the EntityModel. Returns false
* for a simple type, array type, or enum type.
*/
boolean isModelClass() {
return false;
}
/**
* For an entity class or subclass, returns the base entity class; returns
* null in other cases.
*/
ComplexFormat getEntityFormat() {
return null;
}
/**
* Called for an existing format that may not equal the current format for
* the same class.
*
* If this method returns true, then it must have determined one of two
* things:
* - that the old and new formats are equal, and it must have called
* Evolver.useOldFormat; or
* - that the old format can be evolved to the new format, and it must
* have called Evolver.useEvolvedFormat.
*
* If this method returns false, then it must have determined that the
* old format could not be evolved to the new format, and it must have
* called Evolver.addInvalidMutation, addMissingMutation or
* addEvolveError.
*/
abstract boolean evolve(Format newFormat, Evolver evolver);
/**
* Called when a Converter handles evolution of a class, but we may still
* need to evolve the metadata.
*/
boolean evolveMetadata(Format newFormat,
Converter converter,
Evolver evolver) {
return true;
}
/**
* Returns whether this format is the current format for its class. If
* false is returned, this format is setup to evolve to the current format.
*/
final boolean isCurrentVersion() {
return latestFormat == this && !deleted;
}
/**
* Returns whether this format has the same class as the given format,
* irrespective of version changes and renaming.
*/
final boolean isSameClass(Format other) {
return latestFormat == other.latestFormat;
}
/* -- Abstract methods that must be implemented by subclasses. -- */
/**
* Initializes an uninitialized format, initializing its related formats
* (superclass formats and array component formats) first.
*/
abstract void initialize(Catalog catalog,
EntityModel model,
int initVersion);
/**
* Calls catalog.createFormat for formats that this format depends on, or
* that should also be persistent.
*/
abstract void collectRelatedFormats(Catalog catalog,
Map newFormats);
/*
* The remaining methods are used to read objects from data bytes via
* EntityInput, and to write objects as data bytes via EntityOutput.
* Ultimately these methods call methods in the Accessor interface to
* get/set fields in the object. Most methods have a rawAccess parameter
* that determines whether the object is a raw object or a real persistent
* object.
*
* The first group of methods are abstract and must be implemented by
* format classes. The second group have default implementations that
* throw UnsupportedOperationException and may optionally be overridden.
*/
/**
* Creates an array of the format's class of the given length, as if
* Array.newInstance(getType(), len) were called. Formats implement this
* method for specific classes, or call the accessor, to avoid the
* reflection overhead of Array.newInstance.
*/
abstract Object newArray(int len);
/**
* Creates a new instance of the target class using its default
* constructor. Normally this creates an empty object, and readObject() is
* called next to fill in the contents. This is done in two steps to allow
* the instance to be registered by EntityInput before reading the
* contents. This allows the fields in an object or a nested object to
* refer to the parent object in a graph.
*
* Alternatively, this method may read all or the first portion of the
* data, rather than that being done by readObject(). This is required for
* simple types and enums, where the object cannot be created without
* reading the data. In these cases, there is no possibility that the
* parent object will be referenced by the child object in the graph. It
* should not be done in other cases, or the graph references may not be
* maintained faithfully.
*
* Is public only in order to implement the Reader interface. Note that
* this method should only be called directly in raw conversion mode or
* during conversion of an old format. Normally it should be called via
* the getReader method and the Reader interface.
*/
public abstract Object newInstance(EntityInput input, boolean rawAccess)
throws RefreshException;
/**
* Called after newInstance() to read the rest of the data bytes and fill
* in the object contents. If the object was read completely by
* newInstance(), this method does nothing.
*
* Is public only in order to implement the Reader interface. Note that
* this method should only be called directly in raw conversion mode or
* during conversion of an old format. Normally it should be called via
* the getReader method and the Reader interface.
*/
public abstract Object readObject(Object o,
EntityInput input,
boolean rawAccess)
throws RefreshException;
/**
* Writes a given instance of the target class to the output data bytes.
* This is the complement of the newInstance()/readObject() pair.
*/
abstract void writeObject(Object o, EntityOutput output, boolean rawAccess)
throws RefreshException;
/**
* Skips over the object's contents, as if readObject() were called, but
* without returning an object. Used for extracting secondary key bytes
* without having to instantiate the object. For reference types, the
* format ID is read just before calling this method, so this method is
* responsible for skipping everything following the format ID.
*/
abstract void skipContents(RecordInput input)
throws RefreshException;
/* -- More methods that may optionally be overridden by subclasses. -- */
/**
* When extracting a secondary key, called to skip over all fields up to
* the given secondary key field. Returns the format of the key field
* found, or null if the field is not present (nullified) in the object.
*/
Format skipToSecKey(RecordInput input, String keyName)
throws RefreshException {
throw DbCompat.unexpectedState(toString());
}
/**
* Called after skipToSecKey() to copy the data bytes of a singular
* (XXX_TO_ONE) key field.
*/
void copySecKey(RecordInput input, RecordOutput output) {
throw DbCompat.unexpectedState(toString());
}
/**
* Called after skipToSecKey() to copy the data bytes of an array or
* collection (XXX_TO_MANY) key field.
*/
void copySecMultiKey(RecordInput input, Format keyFormat, Set results)
throws RefreshException {
throw DbCompat.unexpectedState(toString());
}
/**
* Nullifies the given key field in the given RawObject -- rawAccess mode
* is implied.
*/
boolean nullifySecKey(Catalog catalog,
Object entity,
String keyName,
Object keyElement) {
throw DbCompat.unexpectedState(toString());
}
/**
* Returns whether the entity's primary key field is null or zero, as
* defined for primary keys that are assigned from a sequence.
*/
boolean isPriKeyNullOrZero(Object o, boolean rawAccess) {
throw DbCompat.unexpectedState(toString());
}
/**
* Gets the primary key field from the given object and writes it to the
* given output data bytes. This is a separate operation because the
* primary key data bytes are stored separately from the rest of the
* record.
*/
void writePriKey(Object o, EntityOutput output, boolean rawAccess)
throws RefreshException {
throw DbCompat.unexpectedState(toString());
}
/**
* Reads the primary key from the given input bytes and sets the primary
* key field in the given object. This is complement of writePriKey().
*
* Is public only in order to implement the Reader interface. Note that
* this method should only be called directly in raw conversion mode or
* during conversion of an old format. Normally it should be called via
* the getReader method and the Reader interface.
*/
public void readPriKey(Object o, EntityInput input, boolean rawAccess)
throws RefreshException {
throw DbCompat.unexpectedState(toString());
}
/**
* For an entity class or subclass, returns the old key name for the given
* key name that has been renamed, or returns the given key name if it has
* not been renamed.
*/
public String getOldKeyName(final String keyName) {
throw DbCompat.unexpectedState(toString());
}
/**
* Validates and returns the simple integer key format for a sequence key
* associated with this format.
*
* For a composite key type, the format of the one and only field is
* returned. For a simple integer type, this format is returned.
* Otherwise (the default implementation), an IllegalArgumentException is
* thrown.
*/
Format getSequenceKeyFormat() {
throw new IllegalArgumentException
("Type not allowed for sequence: " + getClassName());
}
/**
* Converts a RawObject to a current class object and adds the converted
* pair to the converted map.
*/
Object convertRawObject(Catalog catalog,
boolean rawAccess,
RawObject rawObject,
IdentityHashMap converted)
throws RefreshException {
throw DbCompat.unexpectedState(toString());
}
/**
* Currently, only FBigDec will return true. It is a workaround for reading
* the BigDecimal data stored by BigDecimal proxy before je4.1.
*/
public boolean allowEvolveFromProxy() {
return false;
}
public Accessor getAccessor(boolean rawAccess) {
return null;
}
@Override
public String toString() {
final String INDENT = " ";
final String INDENT2 = INDENT + " ";
StringBuilder buf = new StringBuilder(500);
if (isSimple()) {
addTypeHeader(buf, "SimpleType");
buf.append(" primitive=\"");
buf.append(isPrimitive());
buf.append("\"/>\n");
} else if (isEnum()) {
addTypeHeader(buf, "EnumType");
buf.append(">\n");
for (String constant : getEnumConstants()) {
buf.append(INDENT);
buf.append("");
buf.append(constant);
buf.append(" \n");
}
buf.append("\n");
} else if (isArray()) {
addTypeHeader(buf, "ArrayType");
buf.append(" componentId=\"");
buf.append(getComponentType().getVersion());
buf.append("\" componentClass=\"");
buf.append(getComponentType().getClassName());
buf.append("\" dimensions=\"");
buf.append(getDimensions());
buf.append("\"/>\n");
} else {
addTypeHeader(buf, "ComplexType");
Format superType = getSuperType();
if (superType != null) {
buf.append(" superTypeId=\"");
buf.append(superType.getId());
buf.append("\" superTypeClass=\"");
buf.append(superType.getClassName());
buf.append('"');
}
Format proxiedFormat = getProxiedFormat();
if (proxiedFormat != null) {
buf.append(" proxiedTypeId=\"");
buf.append(proxiedFormat.getId());
buf.append("\" proxiedTypeClass=\"");
buf.append(proxiedFormat.getClassName());
buf.append('"');
}
PrimaryKeyMetadata priMeta = null;
Map secondaryKeys = null;
List compositeKeyFields = null;
ClassMetadata clsMeta = getClassMetadata();
if (clsMeta != null) {
compositeKeyFields = clsMeta.getCompositeKeyFields();
priMeta = clsMeta.getPrimaryKey();
secondaryKeys = clsMeta.getSecondaryKeys();
}
buf.append(" kind=\"");
buf.append(isEntity() ? "entity" :
((compositeKeyFields != null) ? "compositeKey" :
"persistent"));
buf.append("\">\n");
Map fields = getFields();
if (fields != null) {
for (RawField field : fields.values()) {
String name = field.getName();
RawType type = field.getType();
buf.append(INDENT);
buf.append(" \n");
}
EntityMetadata entMeta = getEntityMetadata();
if (entMeta != null) {
buf.append(INDENT);
buf.append("\n");
priMeta = entMeta.getPrimaryKey();
if (priMeta != null) {
buf.append(INDENT2);
buf.append(" \n");
}
secondaryKeys = entMeta.getSecondaryKeys();
if (secondaryKeys != null) {
for (SecondaryKeyMetadata secMeta :
secondaryKeys.values()) {
buf.append(INDENT2);
buf.append(" \n");
}
}
buf.append(" \n");
}
}
buf.append("\n");
}
return buf.toString();
}
private void addTypeHeader(StringBuilder buf, String elemName) {
buf.append('<');
buf.append(elemName);
buf.append(" id=\"");
buf.append(getId());
buf.append("\" class=\"");
buf.append(getClassName());
buf.append("\" version=\"");
buf.append(getVersion());
buf.append('"');
Format currVersion = getLatestVersion();
if (currVersion != null) {
buf.append(" currentVersionId=\"");
buf.append(currVersion.getId());
buf.append('"');
}
Format prevVersion = getPreviousVersion();
if (prevVersion != null) {
buf.append(" previousVersionId=\"");
buf.append(prevVersion.getId());
buf.append('"');
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy