0001: /*-
0002: * See the file LICENSE for redistribution information.
0003: *
0004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
0005: *
0006: * $Id: ComplexFormat.java,v 1.30.2.7 2008/01/07 15:14:19 cwl Exp $
0007: */
0008:
0009: package com.sleepycat.persist.impl;
0010:
0011: import java.io.Serializable;
0012: import java.util.ArrayList;
0013: import java.util.Collections;
0014: import java.util.HashMap;
0015: import java.util.HashSet;
0016: import java.util.IdentityHashMap;
0017: import java.util.List;
0018: import java.util.Map;
0019: import java.util.Set;
0020:
0021: import com.sleepycat.persist.evolve.Converter;
0022: import com.sleepycat.persist.evolve.Deleter;
0023: import com.sleepycat.persist.evolve.EntityConverter;
0024: import com.sleepycat.persist.evolve.Mutations;
0025: import com.sleepycat.persist.evolve.Renamer;
0026: import com.sleepycat.persist.model.ClassMetadata;
0027: import com.sleepycat.persist.model.EntityMetadata;
0028: import com.sleepycat.persist.model.FieldMetadata;
0029: import com.sleepycat.persist.model.Relationship;
0030: import com.sleepycat.persist.model.SecondaryKeyMetadata;
0031: import com.sleepycat.persist.raw.RawField;
0032: import com.sleepycat.persist.raw.RawObject;
0033:
0034: /**
0035: * Format for persistent complex classes that are not composite key classes.
0036: * This includes entity classes and subclasses.
0037: *
0038: * @author Mark Hayes
0039: */
0040: public class ComplexFormat extends Format {
0041:
0042: private static final long serialVersionUID = -2847843033590454917L;
0043:
0044: private ClassMetadata clsMeta;
0045: private EntityMetadata entityMeta;
0046: private FieldInfo priKeyField;
0047: private List<FieldInfo> secKeyFields;
0048: private List<FieldInfo> nonKeyFields;
0049: private FieldReader secKeyFieldReader;
0050: private FieldReader nonKeyFieldReader;
0051: private Map<String, String> oldToNewKeyMap;
0052: private Map<String, String> newToOldFieldMap;
0053: private boolean evolveNeeded;
0054: private transient Accessor objAccessor;
0055: private transient Accessor rawAccessor;
0056: private transient Format entityFormat;
0057: private transient Map<String, FieldAddress> secKeyAddresses;
0058: private transient volatile Map<String, RawField> rawFields;
0059: private transient volatile FieldInfo[] rawInputFields;
0060: private transient volatile int[] rawInputLevels;
0061: private transient volatile int rawInputDepth;
0062:
0063: ComplexFormat(Class cls, ClassMetadata clsMeta,
0064: EntityMetadata entityMeta) {
0065: super (cls);
0066: this .clsMeta = clsMeta;
0067: this .entityMeta = entityMeta;
0068: secKeyFields = new ArrayList<FieldInfo>();
0069: nonKeyFields = FieldInfo.getInstanceFields(cls);
0070:
0071: /*
0072: * Validate primary key metadata and move primary key field from
0073: * nonKeyFields to priKeyField.
0074: */
0075: if (clsMeta.getPrimaryKey() != null) {
0076: String fieldName = clsMeta.getPrimaryKey().getName();
0077: FieldInfo field = FieldInfo.getField(nonKeyFields,
0078: fieldName);
0079: if (field == null) {
0080: throw new IllegalArgumentException(
0081: "Primary key field does not exist: "
0082: + getClassName() + '.' + fieldName);
0083: }
0084: nonKeyFields.remove(field);
0085: priKeyField = field;
0086: }
0087:
0088: /*
0089: * Validate secondary key metadata and move secondary key fields from
0090: * nonKeyFields to secKeyFields.
0091: */
0092: if (clsMeta.getSecondaryKeys() != null) {
0093: for (SecondaryKeyMetadata secKeyMeta : clsMeta
0094: .getSecondaryKeys().values()) {
0095: String fieldName = secKeyMeta.getName();
0096: FieldInfo field = FieldInfo.getField(nonKeyFields,
0097: fieldName);
0098: if (field == null) {
0099: throw new IllegalArgumentException(
0100: "Secondary key field does not exist: "
0101: + getClassName() + '.' + fieldName);
0102: }
0103: Class fieldCls = field.getFieldClass();
0104: Relationship rel = secKeyMeta.getRelationship();
0105: if (rel == Relationship.ONE_TO_MANY
0106: || rel == Relationship.MANY_TO_MANY) {
0107: if (!PersistKeyCreator.isManyType(fieldCls)) {
0108: throw new IllegalArgumentException(
0109: "ONE_TO_MANY and MANY_TO_MANY keys must"
0110: + " have an array or Collection type: "
0111: + getClassName() + '.'
0112: + fieldName);
0113: }
0114: } else {
0115: if (PersistKeyCreator.isManyType(fieldCls)) {
0116: throw new IllegalArgumentException(
0117: "ONE_TO_ONE and MANY_TO_ONE keys must not"
0118: + " have an array or Collection type: "
0119: + getClassName() + '.'
0120: + fieldName);
0121: }
0122: }
0123: nonKeyFields.remove(field);
0124: secKeyFields.add(field);
0125: }
0126: }
0127:
0128: /* Sort each group of fields by name. */
0129: Collections.sort(secKeyFields);
0130: Collections.sort(nonKeyFields);
0131: }
0132:
0133: @Override
0134: void migrateFromBeta(Map<String, Format> formatMap) {
0135: super .migrateFromBeta(formatMap);
0136: if (priKeyField != null) {
0137: priKeyField.migrateFromBeta(formatMap);
0138: }
0139: for (FieldInfo field : secKeyFields) {
0140: field.migrateFromBeta(formatMap);
0141: }
0142: for (FieldInfo field : nonKeyFields) {
0143: field.migrateFromBeta(formatMap);
0144: }
0145: }
0146:
0147: /**
0148: * Returns getSuperFormat cast to ComplexFormat. It is guaranteed that all
0149: * super formats of a ComplexFormat are a ComplexFormat.
0150: */
0151: private ComplexFormat getComplexSuper() {
0152: return (ComplexFormat) getSuperFormat();
0153: }
0154:
0155: /**
0156: * Returns getLatestVersion cast to ComplexFormat. It is guaranteed that
0157: * all versions of a ComplexFormat are a ComplexFormat.
0158: */
0159: private ComplexFormat getComplexLatest() {
0160: return (ComplexFormat) getLatestVersion();
0161: }
0162:
0163: String getPriKeyField() {
0164: if (clsMeta.getPrimaryKey() != null) {
0165: return clsMeta.getPrimaryKey().getName();
0166: } else {
0167: return null;
0168: }
0169: }
0170:
0171: @Override
0172: boolean isEntity() {
0173: return clsMeta.isEntityClass();
0174: }
0175:
0176: @Override
0177: boolean isModelClass() {
0178: return true;
0179: }
0180:
0181: @Override
0182: ClassMetadata getClassMetadata() {
0183: return clsMeta;
0184: }
0185:
0186: @Override
0187: EntityMetadata getEntityMetadata() {
0188: return entityMeta;
0189: }
0190:
0191: @Override
0192: Format getEntityFormat() {
0193: if (isInitialized()) {
0194: return entityFormat;
0195: } else {
0196: for (Format format = this ; format != null; format = format
0197: .getSuperFormat()) {
0198: if (format.isEntity()) {
0199: return format;
0200: }
0201: }
0202: return null;
0203: }
0204: }
0205:
0206: @Override
0207: void setEvolveNeeded(boolean needed) {
0208: evolveNeeded = needed;
0209: }
0210:
0211: @Override
0212: boolean getEvolveNeeded() {
0213: return evolveNeeded;
0214: }
0215:
0216: @Override
0217: public Map<String, RawField> getFields() {
0218:
0219: /*
0220: * Synchronization is not required since rawFields is immutable. If
0221: * by chance we create two maps when two threads execute this block, no
0222: * harm is done. But be sure to assign the rawFields field only after
0223: * the map is fully populated.
0224: */
0225: if (rawFields == null) {
0226: Map<String, RawField> map = new HashMap<String, RawField>();
0227: if (priKeyField != null) {
0228: map.put(priKeyField.getName(), priKeyField);
0229: }
0230: for (RawField field : secKeyFields) {
0231: map.put(field.getName(), field);
0232: }
0233: for (RawField field : nonKeyFields) {
0234: map.put(field.getName(), field);
0235: }
0236: rawFields = map;
0237: }
0238: return rawFields;
0239: }
0240:
0241: @Override
0242: void collectRelatedFormats(Catalog catalog,
0243: Map<String, Format> newFormats) {
0244: Class cls = getType();
0245: /* Collect field formats. */
0246: if (priKeyField != null) {
0247: priKeyField.collectRelatedFormats(catalog, newFormats);
0248: }
0249: for (FieldInfo field : secKeyFields) {
0250: field.collectRelatedFormats(catalog, newFormats);
0251: }
0252: for (FieldInfo field : nonKeyFields) {
0253: field.collectRelatedFormats(catalog, newFormats);
0254: }
0255: /* Collect TO_MANY secondary key field element class formats. */
0256: if (entityMeta != null) {
0257: for (SecondaryKeyMetadata secKeyMeta : entityMeta
0258: .getSecondaryKeys().values()) {
0259: String elemClsName = secKeyMeta.getElementClassName();
0260: if (elemClsName != null) {
0261: Class elemCls = SimpleCatalog
0262: .keyClassForName(elemClsName);
0263: catalog.createFormat(elemCls, newFormats);
0264: }
0265: }
0266: }
0267: /* Recursively collect superclass formats. */
0268: Class super Cls = cls.getSuperclass();
0269: if (super Cls != Object.class) {
0270: Format super Format = catalog.createFormat(super Cls,
0271: newFormats);
0272: if (!(super Format instanceof ComplexFormat)) {
0273: throw new IllegalArgumentException(
0274: "The superclass of a complex type must not be a"
0275: + " composite key class or a simple type class: "
0276: + super Cls.getName());
0277: }
0278: }
0279: /* Collect proxied format. */
0280: String proxiedClsName = clsMeta.getProxiedClassName();
0281: if (proxiedClsName != null) {
0282: catalog.createFormat(proxiedClsName, newFormats);
0283: }
0284: }
0285:
0286: @Override
0287: void initialize(Catalog catalog, int initVersion) {
0288: Class type = getType();
0289: boolean useEnhanced = false;
0290: if (type != null) {
0291: useEnhanced = EnhancedAccessor.isEnhanced(type);
0292: }
0293: /* Initialize all fields. */
0294: if (priKeyField != null) {
0295: priKeyField.initialize(catalog, initVersion);
0296: }
0297: for (FieldInfo field : secKeyFields) {
0298: field.initialize(catalog, initVersion);
0299: }
0300: for (FieldInfo field : nonKeyFields) {
0301: field.initialize(catalog, initVersion);
0302: }
0303: /* Set the superclass format for a new (never initialized) format. */
0304: ComplexFormat super Format = getComplexSuper();
0305: if (type != null && super Format == null) {
0306: Class super Cls = type.getSuperclass();
0307: if (super Cls != Object.class) {
0308: super Format = (ComplexFormat) catalog
0309: .getFormat(super Cls.getName());
0310: setSuperFormat(super Format);
0311: }
0312: }
0313: /* Initialize the superclass format and validate the super accessor. */
0314: if (super Format != null) {
0315: super Format.initializeIfNeeded(catalog);
0316: Accessor super Accessor = super Format.objAccessor;
0317: if (type != null && super Accessor != null) {
0318: if (useEnhanced) {
0319: if (!(super Accessor instanceof EnhancedAccessor)) {
0320: throw new IllegalStateException(
0321: "The superclass of an enhanced class must also "
0322: + "be enhanced: "
0323: + getClassName() + " extends "
0324: + super Format.getClassName());
0325: }
0326: } else {
0327: if (!(super Accessor instanceof ReflectionAccessor)) {
0328: throw new IllegalStateException(
0329: "The superclass of an unenhanced class must "
0330: + "not be enhanced: "
0331: + getClassName() + " extends "
0332: + super Format.getClassName());
0333: }
0334: }
0335: }
0336: }
0337: /* Find entity format, if any. */
0338: for (Format format = this ; format != null; format = format
0339: .getSuperFormat()) {
0340: if (format.isEntity()) {
0341: entityFormat = format;
0342: break;
0343: }
0344: }
0345: /* Create the accessors. */
0346: if (type != null) {
0347: if (useEnhanced) {
0348: objAccessor = new EnhancedAccessor(catalog, type, this );
0349: } else {
0350: Accessor super ObjAccessor = (super Format != null) ? super Format.objAccessor
0351: : null;
0352: objAccessor = new ReflectionAccessor(catalog, type,
0353: super ObjAccessor, priKeyField, secKeyFields,
0354: nonKeyFields);
0355: }
0356: }
0357: Accessor super RawAccessor = (super Format != null) ? super Format.rawAccessor
0358: : null;
0359: rawAccessor = new RawAccessor(this , super RawAccessor,
0360: priKeyField, secKeyFields, nonKeyFields);
0361:
0362: /* Initialize secondary key field addresses. */
0363: EntityMetadata latestEntityMeta = null;
0364: if (entityFormat != null) {
0365: latestEntityMeta = entityFormat.getLatestVersion()
0366: .getEntityMetadata();
0367: }
0368: if (latestEntityMeta != null) {
0369: secKeyAddresses = new HashMap<String, FieldAddress>();
0370: ComplexFormat this Latest = getComplexLatest();
0371: if (this Latest != this ) {
0372: this Latest.initializeIfNeeded(catalog);
0373: }
0374: nextKeyLoop: for (SecondaryKeyMetadata secKeyMeta : latestEntityMeta
0375: .getSecondaryKeys().values()) {
0376: String clsName = secKeyMeta.getDeclaringClassName();
0377: String fieldName = secKeyMeta.getName();
0378: int super Level = 0;
0379: for (ComplexFormat format = this ; format != null; format = format
0380: .getComplexSuper()) {
0381: if (clsName.equals(format.getLatestVersion()
0382: .getClassName())) {
0383: String useFieldName = null;
0384: if (format.newToOldFieldMap != null
0385: && format.newToOldFieldMap
0386: .containsKey(fieldName)) {
0387: useFieldName = format.newToOldFieldMap
0388: .get(fieldName);
0389: } else {
0390: useFieldName = fieldName;
0391: }
0392: boolean isSecField;
0393: int fieldNum;
0394: FieldInfo info = FieldInfo.getField(
0395: format.secKeyFields, useFieldName);
0396: if (info != null) {
0397: isSecField = true;
0398: fieldNum = format.secKeyFields
0399: .indexOf(info);
0400: } else {
0401: isSecField = false;
0402: info = FieldInfo.getField(
0403: format.nonKeyFields, useFieldName);
0404: if (info == null) {
0405: /* Field not present in old format. */
0406: assert this Latest != this ;
0407: this Latest
0408: .checkNewSecKeyInitializer(secKeyMeta);
0409: continue nextKeyLoop;
0410: }
0411: fieldNum = format.nonKeyFields
0412: .indexOf(info);
0413: }
0414: FieldAddress addr = new FieldAddress(
0415: isSecField, fieldNum, super Level,
0416: format, info.getType());
0417: secKeyAddresses.put(secKeyMeta.getKeyName(),
0418: addr);
0419: }
0420: super Level += 1;
0421: }
0422: }
0423: }
0424: }
0425:
0426: /**
0427: * Checks that the type of a new secondary key is not a primitive and that
0428: * the default contructor does not initialize it to a non-null value.
0429: */
0430: private void checkNewSecKeyInitializer(
0431: SecondaryKeyMetadata secKeyMeta) {
0432: if (objAccessor != null) {
0433: FieldAddress addr = secKeyAddresses.get(secKeyMeta
0434: .getKeyName());
0435: Object obj = objAccessor.newInstance();
0436: Object val = objAccessor.getField(obj, addr.fieldNum,
0437: addr.super Level, addr.isSecField);
0438: if (val != null) {
0439: if (addr.keyFormat.isPrimitive()) {
0440: throw new IllegalArgumentException(
0441: "For a new secondary key field the field type must "
0442: + "not be a primitive -- class: "
0443: + secKeyMeta
0444: .getDeclaringClassName()
0445: + " field: " + secKeyMeta.getName());
0446: } else {
0447: throw new IllegalArgumentException(
0448: "For a new secondary key field the default "
0449: + "constructor must not initialize the field to a "
0450: + "non-null value -- class: "
0451: + secKeyMeta
0452: .getDeclaringClassName()
0453: + " field: " + secKeyMeta.getName());
0454: }
0455: }
0456: }
0457: }
0458:
0459: private boolean nullOrEqual(Object o1, Object o2) {
0460: if (o1 == null) {
0461: return o2 == null;
0462: } else {
0463: return o1.equals(o2);
0464: }
0465: }
0466:
0467: @Override
0468: Object newArray(int len) {
0469: return objAccessor.newArray(len);
0470: }
0471:
0472: @Override
0473: public Object newInstance(EntityInput input, boolean rawAccess) {
0474: Accessor accessor = rawAccess ? rawAccessor : objAccessor;
0475: return accessor.newInstance();
0476: }
0477:
0478: @Override
0479: public Object readObject(Object o, EntityInput input,
0480: boolean rawAccess) {
0481: Accessor accessor = rawAccess ? rawAccessor : objAccessor;
0482: accessor.readSecKeyFields(o, input, 0, Accessor.MAX_FIELD_NUM,
0483: -1);
0484: accessor.readNonKeyFields(o, input, 0, Accessor.MAX_FIELD_NUM,
0485: -1);
0486: return o;
0487: }
0488:
0489: @Override
0490: void writeObject(Object o, EntityOutput output, boolean rawAccess) {
0491: Accessor accessor = rawAccess ? rawAccessor : objAccessor;
0492: accessor.writeSecKeyFields(o, output);
0493: accessor.writeNonKeyFields(o, output);
0494: }
0495:
0496: @Override
0497: Object convertRawObject(Catalog catalog, boolean rawAccess,
0498: RawObject rawObject, IdentityHashMap converted) {
0499: /*
0500: * Synchronization is not required since rawInputFields, rawInputLevels
0501: * and rawInputDepth are immutable. If by chance we create duplicate
0502: * values when two threads execute this block, no harm is done. But be
0503: * sure to assign the fields only after the values are fully populated.
0504: */
0505: FieldInfo[] fields = rawInputFields;
0506: int[] levels = rawInputLevels;
0507: int depth = rawInputDepth;
0508: if (fields == null || levels == null || depth == 0) {
0509:
0510: /*
0511: * The volatile fields are not yet set. Prepare to process the
0512: * class hierarchy, storing class formats in order from the highest
0513: * superclass down to the current class.
0514: */
0515: depth = 0;
0516: int nFields = 0;
0517: for (ComplexFormat format = this ; format != null; format = format
0518: .getComplexSuper()) {
0519: nFields += format.getNFields();
0520: depth += 1;
0521: }
0522: ComplexFormat[] hierarchy = new ComplexFormat[depth];
0523: int level = depth;
0524: for (ComplexFormat format = this ; format != null; format = format
0525: .getComplexSuper()) {
0526: level -= 1;
0527: hierarchy[level] = format;
0528: }
0529: assert level == 0;
0530:
0531: /* Populate levels and fields in parallel. */
0532: levels = new int[nFields];
0533: fields = new FieldInfo[nFields];
0534: int index = 0;
0535:
0536: /*
0537: * The primary key is the first field read/written. We use the
0538: * first primary key field encountered going from this class upward
0539: * in the class hierarchy.
0540: */
0541: if (getEntityFormat() != null) {
0542: for (level = depth - 1; level >= 0; level -= 1) {
0543: ComplexFormat format = hierarchy[level];
0544: if (format.priKeyField != null) {
0545: levels[index] = level;
0546: fields[index] = format.priKeyField;
0547: index += 1;
0548: break;
0549: }
0550: }
0551: assert index == 1;
0552: }
0553:
0554: /*
0555: * Secondary key fields are read/written next, from the highest
0556: * base class downward.
0557: */
0558: for (level = 0; level < depth; level += 1) {
0559: ComplexFormat format = hierarchy[level];
0560: for (FieldInfo field : format.secKeyFields) {
0561: levels[index] = level;
0562: fields[index] = field;
0563: index += 1;
0564: }
0565: }
0566:
0567: /*
0568: * Other fields are read/written last, from the highest base class
0569: * downward.
0570: */
0571: for (level = 0; level < depth; level += 1) {
0572: ComplexFormat format = hierarchy[level];
0573: for (FieldInfo field : format.nonKeyFields) {
0574: levels[index] = level;
0575: fields[index] = field;
0576: index += 1;
0577: }
0578: }
0579:
0580: /* We're finished -- update the volatile fields for next time. */
0581: assert index == fields.length;
0582: rawInputFields = fields;
0583: rawInputLevels = levels;
0584: rawInputDepth = depth;
0585: }
0586:
0587: /*
0588: * Create an objects array that is parallel to the fields and levels
0589: * arrays, but contains the RawObject for each slot from which the
0590: * field value can be retrieved. The predetermined level for each
0591: * field determines which RawObject in the instance hierarchy to use.
0592: */
0593: RawObject[] objectsByLevel = new RawObject[depth];
0594: int level = depth;
0595: for (RawObject raw = rawObject; raw != null; raw = raw
0596: .getSuper()) {
0597: if (level == 0) {
0598: throw new IllegalArgumentException(
0599: "RawObject has too many superclasses: "
0600: + rawObject.getType().getClassName());
0601: }
0602: level -= 1;
0603: objectsByLevel[level] = raw;
0604: }
0605: if (level > 0) {
0606: throw new IllegalArgumentException(
0607: "RawObject has too few superclasses: "
0608: + rawObject.getType().getClassName());
0609: }
0610: assert level == 0;
0611: RawObject[] objects = new RawObject[fields.length];
0612: for (int i = 0; i < objects.length; i += 1) {
0613: objects[i] = objectsByLevel[levels[i]];
0614: }
0615:
0616: /* Create the persistent object and convert all RawObject fields. */
0617: EntityInput in = new RawComplexInput(catalog, rawAccess,
0618: converted, fields, objects);
0619: Object o = newInstance(in, rawAccess);
0620: converted.put(rawObject, o);
0621: if (getEntityFormat() != null) {
0622: readPriKey(o, in, rawAccess);
0623: }
0624: return readObject(o, in, rawAccess);
0625: }
0626:
0627: @Override
0628: boolean isPriKeyNullOrZero(Object o, boolean rawAccess) {
0629: Accessor accessor = rawAccess ? rawAccessor : objAccessor;
0630: return accessor.isPriKeyFieldNullOrZero(o);
0631: }
0632:
0633: @Override
0634: void writePriKey(Object o, EntityOutput output, boolean rawAccess) {
0635: Accessor accessor = rawAccess ? rawAccessor : objAccessor;
0636: accessor.writePriKeyField(o, output);
0637: }
0638:
0639: @Override
0640: public void readPriKey(Object o, EntityInput input,
0641: boolean rawAccess) {
0642: Accessor accessor = rawAccess ? rawAccessor : objAccessor;
0643: accessor.readPriKeyField(o, input);
0644: }
0645:
0646: @Override
0647: boolean nullifySecKey(Catalog catalog, Object entity,
0648: String keyName, Object keyElement) {
0649: if (secKeyAddresses == null) {
0650: throw new IllegalStateException();
0651: }
0652: FieldAddress addr = secKeyAddresses.get(keyName);
0653: if (addr != null) {
0654: Object oldVal = rawAccessor.getField(entity, addr.fieldNum,
0655: addr.super Level, addr.isSecField);
0656: if (oldVal != null) {
0657: if (keyElement != null) {
0658: RawObject container = (RawObject) oldVal;
0659: Object[] a1 = container.getElements();
0660: boolean isArray = (a1 != null);
0661: if (!isArray) {
0662: a1 = CollectionProxy.getElements(container);
0663: }
0664: if (a1 != null) {
0665: for (int i = 0; i < a1.length; i += 1) {
0666: if (keyElement.equals(a1[i])) {
0667: int len = a1.length - 1;
0668: Object[] a2 = new Object[len];
0669: System.arraycopy(a1, 0, a2, 0, i);
0670: System.arraycopy(a1, i + 1, a2, i, len
0671: - i);
0672: if (isArray) {
0673: rawAccessor.setField(entity,
0674: addr.fieldNum,
0675: addr.super Level,
0676: addr.isSecField,
0677: new RawObject(container
0678: .getType(), a2));
0679: } else {
0680: CollectionProxy.setElements(
0681: container, a2);
0682: }
0683: return true;
0684: }
0685: }
0686: }
0687: return false;
0688: } else {
0689: rawAccessor.setField(entity, addr.fieldNum,
0690: addr.super Level, addr.isSecField, null);
0691: return true;
0692: }
0693: } else {
0694: return false;
0695: }
0696: } else {
0697: return false;
0698: }
0699: }
0700:
0701: @Override
0702: void skipContents(RecordInput input) {
0703: skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
0704: skipToNonKeyField(input, Accessor.MAX_FIELD_NUM);
0705: }
0706:
0707: @Override
0708: void copySecMultiKey(RecordInput input, Format keyFormat,
0709: Set results) {
0710: CollectionProxy.copyElements(input, this , keyFormat, results);
0711: }
0712:
0713: @Override
0714: Format skipToSecKey(RecordInput input, String keyName) {
0715: if (secKeyAddresses == null) {
0716: throw new IllegalStateException();
0717: }
0718: FieldAddress addr = secKeyAddresses.get(keyName);
0719: if (addr != null) {
0720: if (addr.isSecField) {
0721: addr.clsFormat.skipToSecKeyField(input, addr.fieldNum);
0722: } else {
0723: skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
0724: addr.clsFormat.skipToNonKeyField(input, addr.fieldNum);
0725: }
0726: return addr.keyFormat;
0727: } else {
0728: return null;
0729: }
0730: }
0731:
0732: private int getNFields() {
0733: return ((priKeyField != null) ? 1 : 0) + secKeyFields.size()
0734: + nonKeyFields.size();
0735: }
0736:
0737: private void skipToSecKeyField(RecordInput input, int toFieldNum) {
0738: ComplexFormat super Format = getComplexSuper();
0739: if (super Format != null) {
0740: super Format
0741: .skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
0742: }
0743: int maxNum = Math.min(secKeyFields.size(), toFieldNum);
0744: for (int i = 0; i < maxNum; i += 1) {
0745: input.skipField(secKeyFields.get(i).getType());
0746: }
0747: }
0748:
0749: private void skipToNonKeyField(RecordInput input, int toFieldNum) {
0750: ComplexFormat super Format = getComplexSuper();
0751: if (super Format != null) {
0752: super Format
0753: .skipToNonKeyField(input, Accessor.MAX_FIELD_NUM);
0754: }
0755: int maxNum = Math.min(nonKeyFields.size(), toFieldNum);
0756: for (int i = 0; i < maxNum; i += 1) {
0757: input.skipField(nonKeyFields.get(i).getType());
0758: }
0759: }
0760:
0761: private static class FieldAddress {
0762:
0763: boolean isSecField;
0764: int fieldNum;
0765: int super Level;
0766: ComplexFormat clsFormat;
0767: Format keyFormat;
0768:
0769: FieldAddress(boolean isSecField, int fieldNum, int super Level,
0770: ComplexFormat clsFormat, Format keyFormat) {
0771: this .isSecField = isSecField;
0772: this .fieldNum = fieldNum;
0773: this .super Level = super Level;
0774: this .clsFormat = clsFormat;
0775: this .keyFormat = keyFormat;
0776: }
0777: }
0778:
0779: @Override
0780: boolean evolve(Format newFormatParam, Evolver evolver) {
0781:
0782: /* Disallow evolution to a non-complex format. */
0783: if (!(newFormatParam instanceof ComplexFormat)) {
0784: evolver.addMissingMutation(this , newFormatParam,
0785: "Converter is required when a complex type is changed "
0786: + "to a simple type or enum type");
0787: return false;
0788: }
0789: ComplexFormat newFormat = (ComplexFormat) newFormatParam;
0790: Mutations mutations = evolver.getMutations();
0791: boolean this Changed = false;
0792: boolean super Changed = false;
0793: Map<String, String> allKeyNameMap = new HashMap<String, String>();
0794:
0795: /*
0796: * Evolve all superclass formats, even when a deleted class appears in
0797: * the hierarchy. This ensures that the super format's
0798: * getLatestVersion/getComplexLatest method can be used accurately
0799: * below.
0800: */
0801: for (ComplexFormat oldSuper = getComplexSuper(); oldSuper != null; oldSuper = oldSuper
0802: .getComplexSuper()) {
0803: Converter converter = mutations.getConverter(oldSuper
0804: .getClassName(), oldSuper.getVersion(), null);
0805: if (converter != null) {
0806: evolver
0807: .addMissingMutation(
0808: this ,
0809: newFormatParam,
0810: "Converter is required for this subclass when a "
0811: + "Converter appears on its superclass: "
0812: + converter);
0813: return false;
0814: }
0815: if (!evolver.evolveFormat(oldSuper)) {
0816: return false;
0817: }
0818: if (!oldSuper.isCurrentVersion()) {
0819: if (oldSuper.isDeleted()) {
0820: if (!oldSuper.evolveDeletedClass(evolver)) {
0821: return false;
0822: }
0823: }
0824: if (oldSuper.oldToNewKeyMap != null) {
0825: allKeyNameMap.putAll(oldSuper.oldToNewKeyMap);
0826: }
0827: super Changed = true;
0828: }
0829: }
0830:
0831: /*
0832: * Compare the old and new class hierarhies and decide whether each
0833: * change is allowed or not:
0834: * + Old deleted and removed superclass -- allowed
0835: * + Old empty and removed superclass -- allowed
0836: * + Old non-empty and removed superclass -- not allowed
0837: * + Old superclass repositioned in the hierarchy -- not allowed
0838: * + New inserted superclass -- allowed
0839: */
0840: Class newFormatCls = newFormat.getExistingType();
0841: Class newSuper = newFormatCls;
0842: List<Integer> newLevels = new ArrayList<Integer>();
0843: int newLevel = 0;
0844: newLevels.add(newLevel);
0845:
0846: /*
0847: * When this format has a new superclass, we treat it as a change to
0848: * this format as well as to the superclass hierarchy.
0849: */
0850: if (getSuperFormat() == null) {
0851: if (newFormatCls.getSuperclass() != Object.class) {
0852: this Changed = true;
0853: super Changed = true;
0854: }
0855: } else {
0856: if (!getSuperFormat().getLatestVersion().getClassName()
0857: .equals(newFormatCls.getSuperclass().getName())) {
0858: this Changed = true;
0859: super Changed = true;
0860: }
0861: }
0862:
0863: for (ComplexFormat oldSuper = getComplexSuper(); oldSuper != null; oldSuper = oldSuper
0864: .getComplexSuper()) {
0865:
0866: /* Find the matching superclass in the new hierarchy. */
0867: String oldSuperName = oldSuper.getLatestVersion()
0868: .getClassName();
0869: Class foundNewSuper = null;
0870: int tryNewLevel = newLevel;
0871: for (Class newSuper2 = newSuper.getSuperclass(); newSuper2 != Object.class; newSuper2 = newSuper2
0872: .getSuperclass()) {
0873: tryNewLevel += 1;
0874: if (oldSuperName.equals(newSuper2.getName())) {
0875: foundNewSuper = newSuper2;
0876: newLevel = tryNewLevel;
0877: break;
0878: }
0879: }
0880:
0881: if (foundNewSuper != null) {
0882:
0883: /*
0884: * We found the old superclass in the new hierarchy. Traverse
0885: * through the superclass formats that were skipped over above
0886: * when finding it.
0887: */
0888: for (Class newSuper2 = newSuper.getSuperclass(); newSuper2 != foundNewSuper; newSuper2 = newSuper2
0889: .getSuperclass()) {
0890:
0891: /*
0892: * The class hierarchy changed -- a new class was inserted.
0893: */
0894: super Changed = true;
0895:
0896: /*
0897: * Check that the new formats skipped over above are not at
0898: * a different position in the old hierarchy.
0899: */
0900: for (ComplexFormat oldSuper2 = oldSuper
0901: .getComplexSuper(); oldSuper2 != null; oldSuper2 = oldSuper2
0902: .getComplexSuper()) {
0903: String oldSuper2Name = oldSuper2
0904: .getLatestVersion().getClassName();
0905: if (oldSuper2Name.equals(newSuper2.getName())) {
0906: evolver
0907: .addMissingMutation(
0908: this ,
0909: newFormatParam,
0910: "Class Converter is required when a "
0911: + "superclass is moved in the class "
0912: + "hierarchy: "
0913: + newSuper2
0914: .getName());
0915: return false;
0916: }
0917: }
0918: }
0919: newSuper = foundNewSuper;
0920: newLevels.add(newLevel);
0921: } else {
0922:
0923: /*
0924: * We did not find the old superclass in the new hierarchy.
0925: * The class hierarchy changed, since an old class no longer
0926: * appears.
0927: */
0928: super Changed = true;
0929:
0930: /* Check that the old class can be safely removed. */
0931: if (!oldSuper.isDeleted()) {
0932: ComplexFormat oldSuperLatest = oldSuper
0933: .getComplexLatest();
0934: if (oldSuperLatest.getNFields() != 0) {
0935: evolver
0936: .addMissingMutation(
0937: this ,
0938: newFormatParam,
0939: "When a superclass is removed from the class "
0940: + "hierarchy, the superclass or all of its "
0941: + "persistent fields must be deleted with a "
0942: + "Deleter: "
0943: + oldSuperLatest
0944: .getClassName());
0945: return false;
0946: }
0947: }
0948:
0949: if (isEntity() && isCurrentVersion()) {
0950: Map<String, SecondaryKeyMetadata> secKeys = oldSuper.clsMeta
0951: .getSecondaryKeys();
0952: for (FieldInfo field : oldSuper.secKeyFields) {
0953: SecondaryKeyMetadata meta = secKeys.get(field
0954: .getName());
0955: assert meta != null;
0956: allKeyNameMap.put(meta.getKeyName(), null);
0957: }
0958: }
0959:
0960: /*
0961: * Add the DO_NOT_READ_ACCESSOR level to prevent an empty class
0962: * (no persistent fields) from being read via the Accessor.
0963: */
0964: newLevels.add(EvolveReader.DO_NOT_READ_ACCESSOR);
0965: }
0966: }
0967:
0968: /* Make FieldReaders for this format if needed. */
0969: int result = evolveAllFields(newFormat, evolver);
0970: if (result == Evolver.EVOLVE_FAILURE) {
0971: return false;
0972: }
0973: if (result == Evolver.EVOLVE_NEEDED) {
0974: this Changed = true;
0975: }
0976: if (oldToNewKeyMap != null) {
0977: allKeyNameMap.putAll(oldToNewKeyMap);
0978: }
0979:
0980: /* Require new version number if this class was changed. */
0981: if (this Changed
0982: && !evolver
0983: .checkUpdatedVersion(
0984: "Changes to the fields or superclass were detected",
0985: this , newFormat)) {
0986: return false;
0987: }
0988:
0989: /* Rename the secondary databases. */
0990: if (allKeyNameMap.size() > 0 && isEntity()
0991: && isCurrentVersion()) {
0992: for (Map.Entry<String, String> entry : allKeyNameMap
0993: .entrySet()) {
0994: String oldKeyName = entry.getKey();
0995: String newKeyName = entry.getValue();
0996: if (newKeyName != null) {
0997: evolver.renameSecondaryDatabase(this , newFormat,
0998: oldKeyName, newKeyName);
0999: } else {
1000: evolver.deleteSecondaryDatabase(this , oldKeyName);
1001: }
1002: }
1003: }
1004:
1005: /* Use an EvolveReader if needed. */
1006: if (super Changed || this Changed) {
1007: Reader reader = new EvolveReader(newLevels);
1008: evolver.useEvolvedFormat(this , reader, newFormat);
1009: } else {
1010: evolver.useOldFormat(this , newFormat);
1011: }
1012: return true;
1013: }
1014:
1015: @Override
1016: boolean evolveMetadata(Format newFormatParam, Converter converter,
1017: Evolver evolver) {
1018: assert !isDeleted();
1019: assert isEntity();
1020: assert newFormatParam.isEntity();
1021: ComplexFormat newFormat = (ComplexFormat) newFormatParam;
1022:
1023: if (!checkKeyTypeChange(newFormat, entityMeta.getPrimaryKey(),
1024: newFormat.entityMeta.getPrimaryKey(), "primary key",
1025: evolver)) {
1026: return false;
1027: }
1028:
1029: Set<String> deletedKeys;
1030: if (converter instanceof EntityConverter) {
1031: EntityConverter entityConverter = (EntityConverter) converter;
1032: deletedKeys = entityConverter.getDeletedKeys();
1033: } else {
1034: deletedKeys = Collections.emptySet();
1035: }
1036:
1037: Map<String, SecondaryKeyMetadata> oldSecondaryKeys = entityMeta
1038: .getSecondaryKeys();
1039: Map<String, SecondaryKeyMetadata> newSecondaryKeys = newFormat.entityMeta
1040: .getSecondaryKeys();
1041: Set<String> insertedKeys = new HashSet<String>(newSecondaryKeys
1042: .keySet());
1043:
1044: for (SecondaryKeyMetadata oldMeta : oldSecondaryKeys.values()) {
1045: String keyName = oldMeta.getKeyName();
1046: if (deletedKeys.contains(keyName)) {
1047: if (isCurrentVersion()) {
1048: evolver.deleteSecondaryDatabase(this , keyName);
1049: }
1050: } else {
1051: SecondaryKeyMetadata newMeta = newSecondaryKeys
1052: .get(keyName);
1053: if (newMeta == null) {
1054: evolver.addInvalidMutation(this , newFormat,
1055: converter,
1056: "Existing key not found in new entity metadata: "
1057: + keyName);
1058: return false;
1059: }
1060: insertedKeys.remove(keyName);
1061: String keyLabel = "secondary key: " + keyName;
1062: if (!checkKeyTypeChange(newFormat, oldMeta, newMeta,
1063: keyLabel, evolver)) {
1064: return false;
1065: }
1066: if (!checkSecKeyMetadata(newFormat, oldMeta, newMeta,
1067: evolver)) {
1068: return false;
1069: }
1070: }
1071: }
1072:
1073: if (!insertedKeys.isEmpty()) {
1074: evolver
1075: .addEvolveError(
1076: this ,
1077: newFormat,
1078: "Error",
1079: "New keys "
1080: + insertedKeys
1081: + " not allowed when using a Converter with an entity class");
1082: }
1083:
1084: return true;
1085: }
1086:
1087: /**
1088: * Checks that changes to secondary key metadata are legal.
1089: */
1090: private boolean checkSecKeyMetadata(Format newFormat,
1091: SecondaryKeyMetadata oldMeta, SecondaryKeyMetadata newMeta,
1092: Evolver evolver) {
1093: if (oldMeta.getRelationship() != newMeta.getRelationship()) {
1094: evolver.addEvolveError(this , newFormat,
1095: "Change detected in the relate attribute (Relationship) "
1096: + "of a secondary key", "Old key: "
1097: + oldMeta.getKeyName() + " relate: "
1098: + oldMeta.getRelationship() + " new key: "
1099: + newMeta.getKeyName() + " relate: "
1100: + newMeta.getRelationship());
1101: return false;
1102: }
1103: return true;
1104: }
1105:
1106: /**
1107: * Checks that the type of a key field did not change, as known from
1108: * metadata when a class conversion is used.
1109: */
1110: private boolean checkKeyTypeChange(Format newFormat,
1111: FieldMetadata oldMeta, FieldMetadata newMeta,
1112: String keyLabel, Evolver evolver) {
1113: String oldClass = oldMeta.getClassName();
1114: String newClass = newMeta.getClassName();
1115: if (!oldClass.equals(newClass)) {
1116: SimpleCatalog catalog = SimpleCatalog.getInstance();
1117: Format oldType = catalog.getFormat(oldClass);
1118: Format newType = catalog.getFormat(newClass);
1119: if (oldType == null
1120: || newType == null
1121: || ((oldType.getWrapperFormat() == null || oldType
1122: .getWrapperFormat().getId() != newType
1123: .getId()) && (newType.getWrapperFormat() == null || newType
1124: .getWrapperFormat().getId() != oldType
1125: .getId()))) {
1126: evolver
1127: .addEvolveError(
1128: this ,
1129: newFormat,
1130: "Type change detected for " + keyLabel,
1131: "Old field type: "
1132: + oldClass
1133: + " is not compatible with the new type: "
1134: + newClass + " old field: "
1135: + oldMeta.getName()
1136: + " new field: "
1137: + newMeta.getName());
1138: return false;
1139: }
1140: }
1141: return true;
1142: }
1143:
1144: /**
1145: * Special case for creating FieldReaders for a deleted class when it
1146: * appears in the class hierarchy of its non-deleted subclass.
1147: */
1148: private boolean evolveDeletedClass(Evolver evolver) {
1149: assert isDeleted();
1150: if (secKeyFieldReader == null || nonKeyFieldReader == null) {
1151: if (priKeyField != null && getEntityFormat() != null
1152: && !getEntityFormat().isDeleted()) {
1153: evolver
1154: .addEvolveError(
1155: this ,
1156: this ,
1157: "Class containing primary key field was deleted ",
1158: "Primary key is needed in an entity class hierarchy: "
1159: + priKeyField.getName());
1160: return false;
1161: } else {
1162: secKeyFieldReader = new SkipFieldReader(0, secKeyFields);
1163: nonKeyFieldReader = new SkipFieldReader(0, nonKeyFields);
1164: return true;
1165: }
1166: } else {
1167: return true;
1168: }
1169: }
1170:
1171: /**
1172: * Creates a FieldReader for secondary key fields and non-key fields if
1173: * necessary. Checks the primary key field if necessary. Does not evolve
1174: * superclass format fields.
1175: */
1176: private int evolveAllFields(ComplexFormat newFormat, Evolver evolver) {
1177:
1178: assert !isDeleted();
1179: secKeyFieldReader = null;
1180: nonKeyFieldReader = null;
1181: oldToNewKeyMap = null;
1182:
1183: /* Evolve primary key field. */
1184: boolean evolveFailure = false;
1185: boolean evolveNeeded = false;
1186: if (priKeyField != null) {
1187: int result = evolver.evolveRequiredKeyField(this ,
1188: newFormat, priKeyField, newFormat.priKeyField);
1189: if (result == Evolver.EVOLVE_FAILURE) {
1190: evolveFailure = true;
1191: } else if (result == Evolver.EVOLVE_NEEDED) {
1192: evolveNeeded = true;
1193: }
1194: }
1195:
1196: /* Evolve secondary key fields. */
1197: FieldReader reader = evolveFieldList(secKeyFields,
1198: newFormat.secKeyFields, true, newFormat.nonKeyFields,
1199: newFormat, evolver);
1200: if (reader == FieldReader.EVOLVE_FAILURE) {
1201: evolveFailure = true;
1202: } else if (reader != null) {
1203: evolveNeeded = true;
1204: }
1205: if (reader != FieldReader.EVOLVE_NEEDED) {
1206: secKeyFieldReader = reader;
1207: }
1208:
1209: /* Evolve non-key fields. */
1210: reader = evolveFieldList(nonKeyFields, newFormat.nonKeyFields,
1211: false, newFormat.secKeyFields, newFormat, evolver);
1212: if (reader == FieldReader.EVOLVE_FAILURE) {
1213: evolveFailure = true;
1214: } else if (reader != null) {
1215: evolveNeeded = true;
1216: }
1217: if (reader != FieldReader.EVOLVE_NEEDED) {
1218: nonKeyFieldReader = reader;
1219: }
1220:
1221: /* Return result. */
1222: if (evolveFailure) {
1223: return Evolver.EVOLVE_FAILURE;
1224: } else if (evolveNeeded) {
1225: return Evolver.EVOLVE_NEEDED;
1226: } else {
1227: return Evolver.EVOLVE_NONE;
1228: }
1229: }
1230:
1231: /**
1232: * Returns a FieldReader that reads no fields.
1233: *
1234: * Instead of adding a DoNothingFieldReader class, we use a
1235: * MultiFieldReader with an empty field list. We do not add a new
1236: * FieldReader class to avoid changing the catalog format. [#15524]
1237: */
1238: private FieldReader getDoNothingFieldReader() {
1239: List<FieldReader> emptyList = Collections.emptyList();
1240: return new MultiFieldReader(emptyList);
1241: }
1242:
1243: /**
1244: * Evolves a list of fields, either secondary key or non-key fields, for a
1245: * single class format.
1246: *
1247: * @return a FieldReader if field evolution is needed, null if no evolution
1248: * is needed, or FieldReader.EVOLVE_FAILURE if an evolution error occurs.
1249: */
1250: private FieldReader evolveFieldList(List<FieldInfo> oldFields,
1251: List<FieldInfo> newFields, boolean isOldSecKeyField,
1252: List<FieldInfo> otherNewFields, ComplexFormat newFormat,
1253: Evolver evolver) {
1254: Mutations mutations = evolver.getMutations();
1255: boolean evolveFailure = false;
1256: boolean evolveNeeded = false;
1257: boolean readerNeeded = false;
1258: List<FieldReader> fieldReaders = new ArrayList<FieldReader>();
1259: FieldReader currentReader = null;
1260: int prevNewFieldIndex = newFields.size();
1261: int newFieldsMatched = 0;
1262:
1263: /*
1264: * Add FieldReaders to the list in old field storage order, since that
1265: * is the order in which field values must be read.
1266: */
1267: fieldLoop: for (int oldFieldIndex = 0; oldFieldIndex < oldFields
1268: .size(); oldFieldIndex += 1) {
1269:
1270: FieldInfo oldField = oldFields.get(oldFieldIndex);
1271: String oldName = oldField.getName();
1272: SecondaryKeyMetadata oldMeta = null;
1273: if (isOldSecKeyField) {
1274: oldMeta = clsMeta.getSecondaryKeys().get(oldName);
1275: assert oldMeta != null;
1276: }
1277:
1278: /* Get field mutations. */
1279: Renamer renamer = mutations.getRenamer(getClassName(),
1280: getVersion(), oldName);
1281: Deleter deleter = mutations.getDeleter(getClassName(),
1282: getVersion(), oldName);
1283: Converter converter = mutations.getConverter(
1284: getClassName(), getVersion(), oldName);
1285: if (deleter != null
1286: && (converter != null || renamer != null)) {
1287: evolver.addInvalidMutation(this , newFormat, deleter,
1288: "Field Deleter is not allowed along with a Renamer or "
1289: + "Converter for the same field: "
1290: + oldName);
1291: evolveFailure = true;
1292: continue fieldLoop;
1293: }
1294:
1295: /*
1296: * Match old and new field by name, taking into account the Renamer
1297: * mutation. If the @SecondaryKey annotation was added or removed,
1298: * the field will have moved from one of the two field lists to the
1299: * other.
1300: */
1301: String newName = (renamer != null) ? renamer.getNewName()
1302: : oldName;
1303: if (!oldName.equals(newName)) {
1304: if (newToOldFieldMap == null) {
1305: newToOldFieldMap = new HashMap<String, String>();
1306: }
1307: newToOldFieldMap.put(newName, oldName);
1308: }
1309: int newFieldIndex = FieldInfo.getFieldIndex(newFields,
1310: newName);
1311: FieldInfo newField = null;
1312: boolean isNewSecKeyField = isOldSecKeyField;
1313: if (newFieldIndex >= 0) {
1314: newField = newFields.get(newFieldIndex);
1315: } else {
1316: newFieldIndex = FieldInfo.getFieldIndex(otherNewFields,
1317: newName);
1318: if (newFieldIndex >= 0) {
1319: newField = otherNewFields.get(newFieldIndex);
1320: isNewSecKeyField = !isOldSecKeyField;
1321: }
1322: evolveNeeded = true;
1323: readerNeeded = true;
1324: }
1325:
1326: /* Apply field Deleter and continue. */
1327: if (deleter != null) {
1328: if (newField != null) {
1329: evolver.addInvalidMutation(this , newFormat,
1330: deleter,
1331: "Field Deleter is not allowed when the persistent "
1332: + "field is still present: "
1333: + oldName);
1334: evolveFailure = true;
1335: }
1336: /* A SkipFieldReader can read multiple sequential fields. */
1337: if (currentReader instanceof SkipFieldReader
1338: && currentReader.acceptField(oldFieldIndex,
1339: newFieldIndex, isNewSecKeyField)) {
1340: currentReader.addField(oldField);
1341: } else {
1342: currentReader = new SkipFieldReader(oldFieldIndex,
1343: oldField);
1344: fieldReaders.add(currentReader);
1345: readerNeeded = true;
1346: evolveNeeded = true;
1347: }
1348: if (isOldSecKeyField) {
1349: if (oldToNewKeyMap == null) {
1350: oldToNewKeyMap = new HashMap<String, String>();
1351: }
1352: oldToNewKeyMap.put(oldMeta.getKeyName(), null);
1353: }
1354: continue fieldLoop;
1355: } else {
1356: if (newField == null) {
1357: evolver.addMissingMutation(this , newFormat,
1358: "Field is not present or not persistent: "
1359: + oldName);
1360: evolveFailure = true;
1361: continue fieldLoop;
1362: }
1363: }
1364:
1365: /*
1366: * The old field corresponds to a known new field, and no Deleter
1367: * mutation applies.
1368: */
1369: newFieldsMatched += 1;
1370:
1371: /* Get and process secondary key metadata changes. */
1372: SecondaryKeyMetadata newMeta = null;
1373: if (isOldSecKeyField && isNewSecKeyField) {
1374: newMeta = newFormat.clsMeta.getSecondaryKeys().get(
1375: newName);
1376: assert newMeta != null;
1377:
1378: /* Validate metadata changes. */
1379: if (!checkSecKeyMetadata(newFormat, oldMeta, newMeta,
1380: evolver)) {
1381: evolveFailure = true;
1382: continue fieldLoop;
1383: }
1384:
1385: /*
1386: * Check for a renamed key and save the old-to-new mapping for
1387: * use in renaming the secondary database and for key
1388: * extraction.
1389: */
1390: String oldKeyName = oldMeta.getKeyName();
1391: String newKeyName = newMeta.getKeyName();
1392: if (!oldKeyName.equals(newKeyName)) {
1393: if (oldToNewKeyMap == null) {
1394: oldToNewKeyMap = new HashMap<String, String>();
1395: }
1396: oldToNewKeyMap.put(oldName, newName);
1397: evolveNeeded = true;
1398: }
1399: } else if (isOldSecKeyField && !isNewSecKeyField) {
1400: if (oldToNewKeyMap == null) {
1401: oldToNewKeyMap = new HashMap<String, String>();
1402: }
1403: oldToNewKeyMap.put(oldMeta.getKeyName(), null);
1404: }
1405:
1406: /* Apply field Converter and continue. */
1407: if (converter != null) {
1408: if (isOldSecKeyField) {
1409: evolver.addInvalidMutation(this , newFormat,
1410: converter,
1411: "Field Converter is not allowed for secondary key "
1412: + "fields: " + oldName);
1413: evolveFailure = true;
1414: } else {
1415: currentReader = new ConvertFieldReader(converter,
1416: oldFieldIndex, newFieldIndex,
1417: isNewSecKeyField);
1418: fieldReaders.add(currentReader);
1419: readerNeeded = true;
1420: evolveNeeded = true;
1421: }
1422: continue fieldLoop;
1423: }
1424:
1425: /*
1426: * Evolve the declared version of the field format and all versions
1427: * more recent, and the formats for all of their subclasses. While
1428: * we're at it, check to see if all possible classes are converted.
1429: */
1430: boolean allClassesConverted = true;
1431: Format oldFieldFormat = oldField.getType();
1432: for (Format formatVersion = oldFieldFormat
1433: .getLatestVersion(); true; formatVersion = formatVersion
1434: .getPreviousVersion()) {
1435: assert formatVersion != null;
1436: if (!evolver.evolveFormat(formatVersion)) {
1437: evolveFailure = true;
1438: continue fieldLoop;
1439: }
1440: if (!formatVersion.isNew()
1441: && !evolver.isClassConverted(formatVersion)) {
1442: allClassesConverted = false;
1443: }
1444: Set<Format> subclassFormats = evolver
1445: .getSubclassFormats(formatVersion);
1446: if (subclassFormats != null) {
1447: for (Format format2 : subclassFormats) {
1448: if (!evolver.evolveFormat(format2)) {
1449: evolveFailure = true;
1450: continue fieldLoop;
1451: }
1452: if (!format2.isNew()
1453: && !evolver.isClassConverted(format2)) {
1454: allClassesConverted = false;
1455: }
1456: }
1457: }
1458: if (formatVersion == oldFieldFormat) {
1459: break;
1460: }
1461: }
1462:
1463: /*
1464: * Check for compatible field types and apply a field widener if
1465: * needed. If no widener is needed, fall through and apply a
1466: * PlainFieldReader.
1467: */
1468: Format oldLatestFormat = oldFieldFormat.getLatestVersion();
1469: Format newFieldFormat = newField.getType();
1470: if (oldLatestFormat.getClassName().equals(
1471: newFieldFormat.getClassName())
1472: && !oldLatestFormat.isDeleted()) {
1473: /* Formats are identical. Fall through. */
1474: } else if (allClassesConverted) {
1475: /* All old classes will be converted. Fall through. */
1476: evolveNeeded = true;
1477: } else if (WidenerInput.isWideningSupported(
1478: oldLatestFormat, newFieldFormat, isOldSecKeyField)) {
1479: /* Apply field widener and continue. */
1480: currentReader = new WidenFieldReader(oldLatestFormat,
1481: newFieldFormat, newFieldIndex, isNewSecKeyField);
1482: fieldReaders.add(currentReader);
1483: readerNeeded = true;
1484: evolveNeeded = true;
1485: continue fieldLoop;
1486: } else {
1487: boolean refWidened = false;
1488: if (!newFieldFormat.isPrimitive()
1489: && !oldLatestFormat.isPrimitive()
1490: && !oldLatestFormat.isDeleted()
1491: && !evolver.isClassConverted(oldLatestFormat)) {
1492: Class oldCls = oldLatestFormat.getExistingType();
1493: Class newCls = newFieldFormat.getExistingType();
1494: if (newCls.isAssignableFrom(oldCls)) {
1495: refWidened = true;
1496: }
1497: }
1498: if (refWidened) {
1499: /* A reference type has been widened. Fall through. */
1500: evolveNeeded = true;
1501: } else {
1502: /* Types are not compatible. */
1503: evolver
1504: .addMissingMutation(
1505: this ,
1506: newFormat,
1507: "Old field type: "
1508: + oldLatestFormat
1509: .getClassName()
1510: + " is not compatible with the new type: "
1511: + newFieldFormat
1512: .getClassName()
1513: + " for field: " + oldName);
1514: evolveFailure = true;
1515: continue fieldLoop;
1516: }
1517: }
1518:
1519: /*
1520: * Old to new field conversion is not needed or is automatic. Read
1521: * fields as if no evolution is needed. A PlainFieldReader can
1522: * read multiple sequential fields.
1523: */
1524: if (currentReader instanceof PlainFieldReader
1525: && currentReader.acceptField(oldFieldIndex,
1526: newFieldIndex, isNewSecKeyField)) {
1527: currentReader.addField(oldField);
1528: } else {
1529: currentReader = new PlainFieldReader(oldFieldIndex,
1530: newFieldIndex, isNewSecKeyField);
1531: fieldReaders.add(currentReader);
1532: }
1533: }
1534:
1535: /*
1536: * If there are new fields, then the old fields must be read using a
1537: * reader, even if the old field list is empty. Using the accessor
1538: * directly will read fields in the wrong order and will read fields
1539: * that were moved between lists (when adding and dropping
1540: * @SecondaryKey). [#15524]
1541: */
1542: if (newFieldsMatched < newFields.size()) {
1543: evolveNeeded = true;
1544: readerNeeded = true;
1545: }
1546:
1547: if (evolveFailure) {
1548: return FieldReader.EVOLVE_FAILURE;
1549: } else if (readerNeeded) {
1550: if (fieldReaders.size() == 0) {
1551: return getDoNothingFieldReader();
1552: } else if (fieldReaders.size() == 1) {
1553: return fieldReaders.get(0);
1554: } else {
1555: return new MultiFieldReader(fieldReaders);
1556: }
1557: } else if (evolveNeeded) {
1558: return FieldReader.EVOLVE_NEEDED;
1559: } else {
1560: return null;
1561: }
1562: }
1563:
1564: /**
1565: * Base class for all FieldReader subclasses. A FieldReader reads one or
1566: * more fields in the old format data, and may call the new format Accessor
1567: * to set the field values.
1568: */
1569: private static abstract class FieldReader implements Serializable {
1570:
1571: static final FieldReader EVOLVE_NEEDED = new PlainFieldReader(
1572: 0, 0, false);
1573: static final FieldReader EVOLVE_FAILURE = new PlainFieldReader(
1574: 0, 0, false);
1575:
1576: private static final long serialVersionUID = 866041475399255164L;
1577:
1578: FieldReader() {
1579: }
1580:
1581: void initialize(Catalog catalog, int initVersion,
1582: ComplexFormat oldParentFormat,
1583: ComplexFormat newParentFormat, boolean isOldSecKey) {
1584: }
1585:
1586: boolean acceptField(int oldFieldIndex, int newFieldIndex,
1587: boolean isNewSecKeyField) {
1588: return false;
1589: }
1590:
1591: void addField(FieldInfo oldField) {
1592: throw new UnsupportedOperationException();
1593: }
1594:
1595: abstract void readFields(Object o, EntityInput input,
1596: Accessor accessor, int super Level);
1597: }
1598:
1599: /**
1600: * Reads a continguous block of fields that have the same format in the old
1601: * and new formats.
1602: */
1603: private static class PlainFieldReader extends FieldReader {
1604:
1605: private static final long serialVersionUID = 1795593463439931402L;
1606:
1607: private int startField;
1608: private int endField;
1609: private boolean secKeyField;
1610: private transient int endOldField;
1611:
1612: PlainFieldReader(int oldFieldIndex, int newFieldIndex,
1613: boolean isNewSecKeyField) {
1614: endOldField = oldFieldIndex;
1615: startField = newFieldIndex;
1616: endField = newFieldIndex;
1617: secKeyField = isNewSecKeyField;
1618: }
1619:
1620: @Override
1621: boolean acceptField(int oldFieldIndex, int newFieldIndex,
1622: boolean isNewSecKeyField) {
1623: return oldFieldIndex == endOldField + 1
1624: && newFieldIndex == endField + 1
1625: && secKeyField == isNewSecKeyField;
1626: }
1627:
1628: @Override
1629: void addField(FieldInfo oldField) {
1630: endField += 1;
1631: endOldField += 1;
1632: }
1633:
1634: @Override
1635: final void readFields(Object o, EntityInput input,
1636: Accessor accessor, int super Level) {
1637: if (secKeyField) {
1638: accessor.readSecKeyFields(o, input, startField,
1639: endField, super Level);
1640: } else {
1641: accessor.readNonKeyFields(o, input, startField,
1642: endField, super Level);
1643: }
1644: }
1645: }
1646:
1647: /**
1648: * Skips a continguous block of fields that exist in the old format but not
1649: * in the new format.
1650: */
1651: private static class SkipFieldReader extends FieldReader {
1652:
1653: private static final long serialVersionUID = -3060281692155253098L;
1654:
1655: private List<Format> fieldFormats;
1656: private transient int endField;
1657:
1658: SkipFieldReader(int startField, List<FieldInfo> fields) {
1659: endField = startField + fields.size() - 1;
1660: fieldFormats = new ArrayList<Format>(fields.size());
1661: for (FieldInfo field : fields) {
1662: fieldFormats.add(field.getType());
1663: }
1664: }
1665:
1666: SkipFieldReader(int startField, FieldInfo oldField) {
1667: endField = startField;
1668: fieldFormats = new ArrayList<Format>();
1669: fieldFormats.add(oldField.getType());
1670: }
1671:
1672: @Override
1673: boolean acceptField(int oldFieldIndex, int newFieldIndex,
1674: boolean isNewSecKeyField) {
1675: return oldFieldIndex == endField + 1;
1676: }
1677:
1678: @Override
1679: void addField(FieldInfo oldField) {
1680: endField += 1;
1681: fieldFormats.add(oldField.getType());
1682: }
1683:
1684: @Override
1685: final void readFields(Object o, EntityInput input,
1686: Accessor accessor, int super Level) {
1687: for (Format format : fieldFormats) {
1688: input.skipField(format);
1689: }
1690: }
1691: }
1692:
1693: /**
1694: * Converts a single field using a field Converter.
1695: */
1696: private static class ConvertFieldReader extends FieldReader {
1697:
1698: private static final long serialVersionUID = 8736410481633998710L;
1699:
1700: private Converter converter;
1701: private int oldFieldNum;
1702: private int fieldNum;
1703: private boolean secKeyField;
1704: private transient Format oldFormat;
1705: private transient Format newFormat;
1706:
1707: ConvertFieldReader(Converter converter, int oldFieldIndex,
1708: int newFieldIndex, boolean isNewSecKeyField) {
1709: this .converter = converter;
1710: oldFieldNum = oldFieldIndex;
1711: fieldNum = newFieldIndex;
1712: secKeyField = isNewSecKeyField;
1713: }
1714:
1715: @Override
1716: void initialize(Catalog catalog, int initVersion,
1717: ComplexFormat oldParentFormat,
1718: ComplexFormat newParentFormat, boolean isOldSecKey) {
1719:
1720: /*
1721: * The oldFieldNum field was added as part of a bug fix. If not
1722: * present in this version of the catalog, we assume it is equal to
1723: * the new field index. The code prior to the bug fix assumes the
1724: * old and new fields have the same index. [#15797]
1725: */
1726: if (initVersion < 1) {
1727: oldFieldNum = fieldNum;
1728: }
1729:
1730: if (isOldSecKey) {
1731: oldFormat = oldParentFormat.secKeyFields.get(
1732: oldFieldNum).getType();
1733: } else {
1734: oldFormat = oldParentFormat.nonKeyFields.get(
1735: oldFieldNum).getType();
1736: }
1737: if (secKeyField) {
1738: newFormat = newParentFormat.secKeyFields.get(fieldNum)
1739: .getType();
1740: } else {
1741: newFormat = newParentFormat.nonKeyFields.get(fieldNum)
1742: .getType();
1743: }
1744: }
1745:
1746: @Override
1747: final void readFields(Object o, EntityInput input,
1748: Accessor accessor, int super Level) {
1749:
1750: /* Create and read the old format instance in raw mode. */
1751: boolean currentRawMode = input.setRawAccess(true);
1752: Object value;
1753: try {
1754: if (oldFormat.isPrimitive()) {
1755: value = input.readKeyObject(oldFormat);
1756: } else {
1757: value = input.readObject();
1758: }
1759: } finally {
1760: input.setRawAccess(currentRawMode);
1761: }
1762:
1763: /* Convert the raw instance to the current format. */
1764: Catalog catalog = input.getCatalog();
1765: value = converter.getConversion().convert(value);
1766:
1767: /* Use a RawSingleInput to convert and type-check the value. */
1768: EntityInput rawInput = new RawSingleInput(catalog,
1769: currentRawMode, null, value, newFormat);
1770:
1771: if (secKeyField) {
1772: accessor.readSecKeyFields(o, rawInput, fieldNum,
1773: fieldNum, super Level);
1774: } else {
1775: accessor.readNonKeyFields(o, rawInput, fieldNum,
1776: fieldNum, super Level);
1777: }
1778: }
1779: }
1780:
1781: /**
1782: * Widens a single field using a field Converter.
1783: */
1784: private static class WidenFieldReader extends FieldReader {
1785:
1786: private static final long serialVersionUID = -2054520670170407282L;
1787:
1788: private int fromFormatId;
1789: private int toFormatId;
1790: private int fieldNum;
1791: private boolean secKeyField;
1792:
1793: WidenFieldReader(Format oldFormat, Format newFormat,
1794: int newFieldIndex, boolean isNewSecKeyField) {
1795: fromFormatId = oldFormat.getId();
1796: toFormatId = newFormat.getId();
1797: fieldNum = newFieldIndex;
1798: secKeyField = isNewSecKeyField;
1799: }
1800:
1801: @Override
1802: final void readFields(Object o, EntityInput input,
1803: Accessor accessor, int super Level) {
1804:
1805: /* The Accessor reads the field value from a WidenerInput. */
1806: EntityInput widenerInput = new WidenerInput(input,
1807: fromFormatId, toFormatId);
1808:
1809: if (secKeyField) {
1810: accessor.readSecKeyFields(o, widenerInput, fieldNum,
1811: fieldNum, super Level);
1812: } else {
1813: accessor.readNonKeyFields(o, widenerInput, fieldNum,
1814: fieldNum, super Level);
1815: }
1816: }
1817: }
1818:
1819: /**
1820: * A FieldReader composed of other FieldReaders, and that calls them in
1821: * sequence. Used when more than one FieldReader is needed for a list of
1822: * fields.
1823: */
1824: private static class MultiFieldReader extends FieldReader {
1825:
1826: private static final long serialVersionUID = -6035976787562441473L;
1827:
1828: private List<FieldReader> subReaders;
1829:
1830: MultiFieldReader(List<FieldReader> subReaders) {
1831: this .subReaders = subReaders;
1832: }
1833:
1834: @Override
1835: void initialize(Catalog catalog, int initVersion,
1836: ComplexFormat oldParentFormat,
1837: ComplexFormat newParentFormat, boolean isOldSecKey) {
1838: for (FieldReader reader : subReaders) {
1839: reader.initialize(catalog, initVersion,
1840: oldParentFormat, newParentFormat, isOldSecKey);
1841: }
1842: }
1843:
1844: @Override
1845: final void readFields(Object o, EntityInput input,
1846: Accessor accessor, int super Level) {
1847: for (FieldReader reader : subReaders) {
1848: reader.readFields(o, input, accessor, super Level);
1849: }
1850: }
1851: }
1852:
1853: /**
1854: * The Reader for evolving ComplexFormat instances. Reads the old format
1855: * data one class (one level in the class hierarchy) at a time. If an
1856: * Accessor is used at a given level, the Accessor is used for the
1857: * corresponding level in the new class hierarchy (classes may be
1858: * inserted/deleted during evolution). At each level, a FieldReader is
1859: * called to evolve the secondary key and non-key lists of fields.
1860: */
1861: private static class EvolveReader implements Reader {
1862:
1863: static final int DO_NOT_READ_ACCESSOR = Integer.MAX_VALUE;
1864:
1865: private static final long serialVersionUID = -1016140948306913283L;
1866:
1867: private transient ComplexFormat newFormat;
1868:
1869: /**
1870: * oldHierarchy contains the formats of the old class hierarchy in most
1871: * to least derived class order.
1872: */
1873: private transient ComplexFormat[] oldHierarchy;
1874:
1875: /**
1876: * newHierarchyLevels contains the corresponding level in the new
1877: * hierarchy for each format in oldHierarchy. newHierarchyLevels is
1878: * indexed by the oldHierarchy index.
1879: */
1880: private int[] newHierarchyLevels;
1881:
1882: EvolveReader(List<Integer> newHierarchyLevelsList) {
1883: int oldDepth = newHierarchyLevelsList.size();
1884: newHierarchyLevels = new int[oldDepth];
1885: newHierarchyLevelsList.toArray();
1886: for (int i = 0; i < oldDepth; i += 1) {
1887: newHierarchyLevels[i] = newHierarchyLevelsList.get(i);
1888: }
1889: }
1890:
1891: public void initializeReader(Catalog catalog, int initVersion,
1892: Format oldFormatParam) {
1893:
1894: ComplexFormat oldFormat = (ComplexFormat) oldFormatParam;
1895: newFormat = oldFormat.getComplexLatest();
1896: newFormat.initializeIfNeeded(catalog);
1897:
1898: /* Create newHierarchy array. */
1899: int newDepth = 0;
1900: for (Format format = newFormat; format != null; format = format
1901: .getSuperFormat()) {
1902: newDepth += 1;
1903: }
1904: ComplexFormat[] newHierarchy = new ComplexFormat[newDepth];
1905: int level = 0;
1906: for (ComplexFormat format = newFormat; format != null; format = format
1907: .getComplexSuper()) {
1908: newHierarchy[level] = format;
1909: level += 1;
1910: }
1911: assert level == newDepth;
1912:
1913: /* Create oldHierarchy array and initialize FieldReaders. */
1914: int oldDepth = newHierarchyLevels.length;
1915: oldHierarchy = new ComplexFormat[oldDepth];
1916: level = 0;
1917: for (ComplexFormat oldFormat2 = oldFormat; oldFormat2 != null; oldFormat2 = oldFormat2
1918: .getComplexSuper()) {
1919: oldHierarchy[level] = oldFormat2;
1920: int level2 = newHierarchyLevels[level];
1921: ComplexFormat newFormat2 = (level2 != DO_NOT_READ_ACCESSOR) ? newHierarchy[level2]
1922: : null;
1923: level += 1;
1924: if (oldFormat2.secKeyFieldReader != null) {
1925: oldFormat2.secKeyFieldReader.initialize(catalog,
1926: initVersion, oldFormat2, newFormat2, true);
1927: }
1928: if (oldFormat2.nonKeyFieldReader != null) {
1929: oldFormat2.nonKeyFieldReader.initialize(catalog,
1930: initVersion, oldFormat2, newFormat2, false);
1931: }
1932: }
1933: assert level == oldDepth;
1934: }
1935:
1936: public Object newInstance(EntityInput input, boolean rawAccess) {
1937: return newFormat.newInstance(input, rawAccess);
1938: }
1939:
1940: public void readPriKey(Object o, EntityInput input,
1941: boolean rawAccess) {
1942: /* No conversion necessary for primary keys. */
1943: newFormat.readPriKey(o, input, rawAccess);
1944: }
1945:
1946: public Object readObject(Object o, EntityInput input,
1947: boolean rawAccess) {
1948:
1949: /* Use the Accessor for the new format. */
1950: Accessor accessor = rawAccess ? newFormat.rawAccessor
1951: : newFormat.objAccessor;
1952:
1953: /* Read old format fields from the top-most class downward. */
1954: int maxMinusOne = oldHierarchy.length - 1;
1955:
1956: /* Read secondary key fields with the adjusted superclass level. */
1957: for (int i = maxMinusOne; i >= 0; i -= 1) {
1958: FieldReader reader = oldHierarchy[i].secKeyFieldReader;
1959: int newLevel = newHierarchyLevels[i];
1960: if (reader != null) {
1961: reader.readFields(o, input, accessor, newLevel);
1962: } else if (newLevel != DO_NOT_READ_ACCESSOR) {
1963: accessor.readSecKeyFields(o, input, 0,
1964: Accessor.MAX_FIELD_NUM, newLevel);
1965: }
1966: }
1967:
1968: /* Read non-key fields with the adjusted superclass level. */
1969: for (int i = maxMinusOne; i >= 0; i -= 1) {
1970: FieldReader reader = oldHierarchy[i].nonKeyFieldReader;
1971: int newLevel = newHierarchyLevels[i];
1972: if (reader != null) {
1973: reader.readFields(o, input, accessor, newLevel);
1974: } else if (newLevel != DO_NOT_READ_ACCESSOR) {
1975: accessor.readNonKeyFields(o, input, 0,
1976: Accessor.MAX_FIELD_NUM, newLevel);
1977: }
1978: }
1979: return o;
1980: }
1981: }
1982: }
|