KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > persist > impl > ComplexFormat


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: ComplexFormat.java,v 1.30 2006/10/30 21:14:32 bostic Exp $
7  */

8
9 package com.sleepycat.persist.impl;
10
11 import java.io.Serializable JavaDoc;
12 import java.util.ArrayList JavaDoc;
13 import java.util.Collections JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.IdentityHashMap JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import com.sleepycat.persist.evolve.Converter;
22 import com.sleepycat.persist.evolve.Deleter;
23 import com.sleepycat.persist.evolve.EntityConverter;
24 import com.sleepycat.persist.evolve.Mutations;
25 import com.sleepycat.persist.evolve.Renamer;
26 import com.sleepycat.persist.model.ClassMetadata;
27 import com.sleepycat.persist.model.EntityMetadata;
28 import com.sleepycat.persist.model.FieldMetadata;
29 import com.sleepycat.persist.model.Relationship;
30 import com.sleepycat.persist.model.SecondaryKeyMetadata;
31 import com.sleepycat.persist.raw.RawField;
32 import com.sleepycat.persist.raw.RawObject;
33
34 /**
35  * Format for persistent complex classes that are not composite key classes.
36  * This includes entity classes and subclasses.
37  *
38  * @author Mark Hayes
39  */

40 public class ComplexFormat extends Format {
41
42     private static final long serialVersionUID = -2847843033590454917L;
43
44     private ClassMetadata clsMeta;
45     private EntityMetadata entityMeta;
46     private FieldInfo priKeyField;
47     private List JavaDoc<FieldInfo> secKeyFields;
48     private List JavaDoc<FieldInfo> nonKeyFields;
49     private FieldReader secKeyFieldReader;
50     private FieldReader nonKeyFieldReader;
51     private Map JavaDoc<String JavaDoc,String JavaDoc> oldToNewKeyMap;
52     private Map JavaDoc<String JavaDoc,String JavaDoc> newToOldFieldMap;
53     private boolean evolveNeeded;
54     private transient Accessor objAccessor;
55     private transient Accessor rawAccessor;
56     private transient Format entityFormat;
57     private transient Map JavaDoc<String JavaDoc,FieldAddress> secKeyAddresses;
58     private transient volatile Map JavaDoc<String JavaDoc,RawField> rawFields;
59     private transient volatile FieldInfo[] rawInputFields;
60     private transient volatile int[] rawInputLevels;
61     private transient volatile int rawInputDepth;
62
63     ComplexFormat(Class JavaDoc cls,
64                   ClassMetadata clsMeta,
65                   EntityMetadata entityMeta) {
66         super(cls);
67         this.clsMeta = clsMeta;
68         this.entityMeta = entityMeta;
69         secKeyFields = new ArrayList JavaDoc<FieldInfo>();
70         nonKeyFields = FieldInfo.getInstanceFields(cls);
71
72         /*
73          * Validate primary key metadata and move primary key field from
74          * nonKeyFields to priKeyField.
75          */

76         if (clsMeta.getPrimaryKey() != null) {
77             String JavaDoc fieldName = clsMeta.getPrimaryKey().getName();
78             FieldInfo field = FieldInfo.getField(nonKeyFields, fieldName);
79             if (field == null) {
80                 throw new IllegalArgumentException JavaDoc
81                     ("Primary key field does not exist: " +
82                      getClassName() + '.' + fieldName);
83             }
84             nonKeyFields.remove(field);
85             priKeyField = field;
86         }
87
88         /*
89          * Validate secondary key metadata and move secondary key fields from
90          * nonKeyFields to secKeyFields.
91          */

92         if (clsMeta.getSecondaryKeys() != null) {
93             for (SecondaryKeyMetadata secKeyMeta :
94                  clsMeta.getSecondaryKeys().values()) {
95                 String JavaDoc fieldName = secKeyMeta.getName();
96                 FieldInfo field = FieldInfo.getField(nonKeyFields, fieldName);
97                 if (field == null) {
98                     throw new IllegalArgumentException JavaDoc
99                         ("Secondary key field does not exist: " +
100                          getClassName() + '.' + fieldName);
101                 }
102                 Class JavaDoc fieldCls = field.getFieldClass();
103                 Relationship rel = secKeyMeta.getRelationship();
104                 if (rel == Relationship.ONE_TO_MANY ||
105                     rel == Relationship.MANY_TO_MANY) {
106                     if (!PersistKeyCreator.isManyType(fieldCls)) {
107                         throw new IllegalArgumentException JavaDoc
108                             ("ONE_TO_MANY and MANY_TO_MANY keys must" +
109                              " have an array or Collection type: " +
110                              getClassName() + '.' + fieldName);
111                     }
112                 } else {
113                     if (PersistKeyCreator.isManyType(fieldCls)) {
114                         throw new IllegalArgumentException JavaDoc
115                             ("ONE_TO_ONE and MANY_TO_ONE keys must not" +
116                              " have an array or Collection type: " +
117                              getClassName() + '.' + fieldName);
118                     }
119                 }
120                 nonKeyFields.remove(field);
121                 secKeyFields.add(field);
122             }
123         }
124
125         /* Sort each group of fields by name. */
126         Collections.sort(secKeyFields);
127         Collections.sort(nonKeyFields);
128     }
129
130     @Override JavaDoc
131     void migrateFromBeta(Map JavaDoc<String JavaDoc,Format> formatMap) {
132         super.migrateFromBeta(formatMap);
133         if (priKeyField != null) {
134             priKeyField.migrateFromBeta(formatMap);
135         }
136         for (FieldInfo field : secKeyFields) {
137             field.migrateFromBeta(formatMap);
138         }
139         for (FieldInfo field : nonKeyFields) {
140             field.migrateFromBeta(formatMap);
141         }
142     }
143
144     /**
145      * Returns getSuperFormat cast to ComplexFormat. It is guaranteed that all
146      * super formats of a ComplexFormat are a ComplexFormat.
147      */

148     private ComplexFormat getComplexSuper() {
149         return (ComplexFormat) getSuperFormat();
150     }
151
152     /**
153      * Returns getLatestVersion cast to ComplexFormat. It is guaranteed that
154      * all versions of a ComplexFormat are a ComplexFormat.
155      */

156     private ComplexFormat getComplexLatest() {
157         return (ComplexFormat) getLatestVersion();
158     }
159
160     String JavaDoc getPriKeyField() {
161         if (clsMeta.getPrimaryKey() != null) {
162             return clsMeta.getPrimaryKey().getName();
163         } else {
164             return null;
165         }
166     }
167
168     @Override JavaDoc
169     boolean isEntity() {
170         return clsMeta.isEntityClass();
171     }
172
173     @Override JavaDoc
174     boolean isModelClass() {
175         return true;
176     }
177
178     @Override JavaDoc
179     ClassMetadata getClassMetadata() {
180         return clsMeta;
181     }
182
183     @Override JavaDoc
184     EntityMetadata getEntityMetadata() {
185         return entityMeta;
186     }
187
188     @Override JavaDoc
189     Format getEntityFormat() {
190         if (isInitialized()) {
191             return entityFormat;
192         } else {
193             for (Format format = this;
194                  format != null;
195                  format = format.getSuperFormat()) {
196                 if (format.isEntity()) {
197                     return format;
198                 }
199             }
200             return null;
201         }
202     }
203
204     @Override JavaDoc
205     void setEvolveNeeded(boolean needed) {
206         evolveNeeded = needed;
207     }
208
209     @Override JavaDoc
210     boolean getEvolveNeeded() {
211         return evolveNeeded;
212     }
213
214     @Override JavaDoc
215     public Map JavaDoc<String JavaDoc,RawField> getFields() {
216
217         /*
218          * Synchronization is not required since rawFields is immutable. If
219          * by chance we create two maps when two threads execute this block, no
220          * harm is done. But be sure to assign the rawFields field only after
221          * the map is fully populated.
222          */

223         if (rawFields == null) {
224             Map JavaDoc<String JavaDoc,RawField> map = new HashMap JavaDoc<String JavaDoc,RawField>();
225             if (priKeyField != null) {
226                 map.put(priKeyField.getName(), priKeyField);
227             }
228             for (RawField field : secKeyFields) {
229                 map.put(field.getName(), field);
230             }
231             for (RawField field : nonKeyFields) {
232                 map.put(field.getName(), field);
233             }
234             rawFields = map;
235         }
236         return rawFields;
237     }
238
239     @Override JavaDoc
240     void collectRelatedFormats(Catalog catalog,
241                                Map JavaDoc<String JavaDoc,Format> newFormats) {
242         Class JavaDoc cls = getType();
243         /* Collect field formats. */
244         if (priKeyField != null) {
245             priKeyField.collectRelatedFormats(catalog, newFormats);
246         }
247         for (FieldInfo field : secKeyFields) {
248             field.collectRelatedFormats(catalog, newFormats);
249         }
250         for (FieldInfo field : nonKeyFields) {
251             field.collectRelatedFormats(catalog, newFormats);
252         }
253         /* Collect TO_MANY secondary key field element class formats. */
254         if (entityMeta != null) {
255             for (SecondaryKeyMetadata secKeyMeta :
256                  entityMeta.getSecondaryKeys().values()) {
257                 String JavaDoc elemClsName = secKeyMeta.getElementClassName();
258                 if (elemClsName != null) {
259                     Class JavaDoc elemCls =
260                         SimpleCatalog.keyClassForName(elemClsName);
261                     catalog.createFormat(elemCls, newFormats);
262                 }
263             }
264         }
265         /* Recursively collect superclass formats. */
266         Class JavaDoc superCls = cls.getSuperclass();
267         if (superCls != Object JavaDoc.class) {
268             Format superFormat = catalog.createFormat(superCls, newFormats);
269             if (!(superFormat instanceof ComplexFormat)) {
270                 throw new IllegalArgumentException JavaDoc
271                     ("The superclass of a complex type must not be a" +
272                      " composite key class or a simple type class: " +
273                      superCls.getName());
274             }
275         }
276         /* Collect proxied format. */
277         String JavaDoc proxiedClsName = clsMeta.getProxiedClassName();
278         if (proxiedClsName != null) {
279             catalog.createFormat(proxiedClsName, newFormats);
280         }
281     }
282
283     @Override JavaDoc
284     void initialize(Catalog catalog) {
285         Class JavaDoc type = getType();
286         boolean useEnhanced = false;
287         if (type != null) {
288             useEnhanced = EnhancedAccessor.isEnhanced(type);
289         }
290         /* Initialize all fields. */
291         if (priKeyField != null) {
292             priKeyField.initialize(catalog);
293         }
294         for (FieldInfo field : secKeyFields) {
295             field.initialize(catalog);
296         }
297         for (FieldInfo field : nonKeyFields) {
298             field.initialize(catalog);
299         }
300         /* Set the superclass format for a new (never initialized) format. */
301         ComplexFormat superFormat = getComplexSuper();
302         if (type != null && superFormat == null) {
303             Class JavaDoc superCls = type.getSuperclass();
304             if (superCls != Object JavaDoc.class) {
305                 superFormat =
306                     (ComplexFormat) catalog.getFormat(superCls.getName());
307                 setSuperFormat(superFormat);
308             }
309         }
310         /* Initialize the superclass format and validate the super accessor. */
311         if (superFormat != null) {
312             superFormat.initializeIfNeeded(catalog);
313             Accessor superAccessor = superFormat.objAccessor;
314             if (type != null && superAccessor != null) {
315                 if (useEnhanced) {
316                     if (!(superAccessor instanceof EnhancedAccessor)) {
317                         throw new IllegalStateException JavaDoc
318                             ("The superclass of an enhanced class must also " +
319                              "be enhanced: " + getClassName() +
320                              " extends " + superFormat.getClassName());
321                     }
322                 } else {
323                     if (!(superAccessor instanceof ReflectionAccessor)) {
324                         throw new IllegalStateException JavaDoc
325                             ("The superclass of an unenhanced class must " +
326                              "not be enhanced: " + getClassName() +
327                              " extends " + superFormat.getClassName());
328                     }
329                 }
330             }
331         }
332         /* Find entity format, if any. */
333         for (Format format = this;
334              format != null;
335              format = format.getSuperFormat()) {
336             if (format.isEntity()) {
337                 entityFormat = format;
338                 break;
339             }
340         }
341         /* Create the accessors. */
342         if (type != null) {
343             if (useEnhanced) {
344                 objAccessor = new EnhancedAccessor(catalog, type, this);
345             } else {
346                 Accessor superObjAccessor =
347                     (superFormat != null) ? superFormat.objAccessor : null;
348                 objAccessor = new ReflectionAccessor
349                     (catalog, type, superObjAccessor, priKeyField,
350                      secKeyFields, nonKeyFields);
351             }
352         }
353         Accessor superRawAccessor =
354             (superFormat != null) ? superFormat.rawAccessor : null;
355         rawAccessor = new RawAccessor
356             (this, superRawAccessor, priKeyField, secKeyFields, nonKeyFields);
357
358         /* Initialize secondary key field addresses. */
359         EntityMetadata latestEntityMeta = null;
360         if (entityFormat != null) {
361             latestEntityMeta =
362                 entityFormat.getLatestVersion().getEntityMetadata();
363         }
364         if (latestEntityMeta != null) {
365             secKeyAddresses = new HashMap JavaDoc<String JavaDoc,FieldAddress>();
366             ComplexFormat thisLatest = getComplexLatest();
367             if (thisLatest != this) {
368                 thisLatest.initializeIfNeeded(catalog);
369             }
370             nextKeyLoop:
371             for (SecondaryKeyMetadata secKeyMeta :
372                  latestEntityMeta.getSecondaryKeys().values()) {
373                 String JavaDoc clsName = secKeyMeta.getDeclaringClassName();
374                 String JavaDoc fieldName = secKeyMeta.getName();
375                 int superLevel = 0;
376                 for (ComplexFormat format = this;
377                      format != null;
378                      format = format.getComplexSuper()) {
379                     if (clsName.equals
380                             (format.getLatestVersion().getClassName())) {
381                         String JavaDoc useFieldName = null;
382                         if (format.newToOldFieldMap != null &&
383                             format.newToOldFieldMap.containsKey(fieldName)) {
384                             useFieldName =
385                                 format.newToOldFieldMap.get(fieldName);
386                         } else {
387                             useFieldName = fieldName;
388                         }
389                         boolean isSecField;
390                         int fieldNum;
391                         FieldInfo info = FieldInfo.getField
392                             (format.secKeyFields, useFieldName);
393                         if (info != null) {
394                             isSecField = true;
395                             fieldNum = format.secKeyFields.indexOf(info);
396                         } else {
397                             isSecField = false;
398                             info = FieldInfo.getField
399                                 (format.nonKeyFields, useFieldName);
400                             if (info == null) {
401                                 /* Field not present in old format. */
402                                 assert thisLatest != this;
403                                 thisLatest.checkNewSecKeyInitializer
404                                     (secKeyMeta);
405                                 continue nextKeyLoop;
406                             }
407                             fieldNum = format.nonKeyFields.indexOf(info);
408                         }
409                         FieldAddress addr = new FieldAddress
410                             (isSecField, fieldNum, superLevel, format,
411                              info.getType());
412                         secKeyAddresses.put(secKeyMeta.getKeyName(), addr);
413                     }
414                     superLevel += 1;
415                 }
416             }
417         }
418     }
419     
420     /**
421      * Checks that the type of a new secondary key is not a primitive and that
422      * the default contructor does not initialize it to a non-null value.
423      */

424     private void checkNewSecKeyInitializer(SecondaryKeyMetadata secKeyMeta) {
425         if (objAccessor != null) {
426             FieldAddress addr = secKeyAddresses.get(secKeyMeta.getKeyName());
427             Object JavaDoc obj = objAccessor.newInstance();
428             Object JavaDoc val = objAccessor.getField
429                 (obj, addr.fieldNum, addr.superLevel, addr.isSecField);
430             if (val != null) {
431                 if (addr.keyFormat.isPrimitive()) {
432                     throw new IllegalArgumentException JavaDoc
433                         ("For a new secondary key field the field type must " +
434                          "not be a primitive -- class: " +
435                          secKeyMeta.getDeclaringClassName() + " field: " +
436                          secKeyMeta.getName());
437                 } else {
438                     throw new IllegalArgumentException JavaDoc
439                         ("For a new secondary key field the default " +
440                          "constructor must not initialize the field to a " +
441                          "non-null value -- class: " +
442                          secKeyMeta.getDeclaringClassName() + " field: " +
443                          secKeyMeta.getName());
444                 }
445             }
446         }
447     }
448
449     private boolean nullOrEqual(Object JavaDoc o1, Object JavaDoc o2) {
450         if (o1 == null) {
451             return o2 == null;
452         } else {
453             return o1.equals(o2);
454         }
455     }
456     
457     @Override JavaDoc
458     Object JavaDoc newArray(int len) {
459         return objAccessor.newArray(len);
460     }
461
462     @Override JavaDoc
463     public Object JavaDoc newInstance(EntityInput input, boolean rawAccess) {
464         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
465         return accessor.newInstance();
466     }
467
468     @Override JavaDoc
469     public Object JavaDoc readObject(Object JavaDoc o, EntityInput input, boolean rawAccess) {
470         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
471         accessor.readSecKeyFields(o, input, 0, Accessor.MAX_FIELD_NUM, -1);
472         accessor.readNonKeyFields(o, input, 0, Accessor.MAX_FIELD_NUM, -1);
473         return o;
474     }
475
476     @Override JavaDoc
477     void writeObject(Object JavaDoc o, EntityOutput output, boolean rawAccess) {
478         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
479         accessor.writeSecKeyFields(o, output);
480         accessor.writeNonKeyFields(o, output);
481     }
482
483     @Override JavaDoc
484     Object JavaDoc convertRawObject(Catalog catalog,
485                             boolean rawAccess,
486                             RawObject rawObject,
487                             IdentityHashMap JavaDoc converted) {
488         /*
489          * Synchronization is not required since rawInputFields, rawInputLevels
490          * and rawInputDepth are immutable. If by chance we create duplicate
491          * values when two threads execute this block, no harm is done. But be
492          * sure to assign the fields only after the values are fully populated.
493          */

494         FieldInfo[] fields = rawInputFields;
495         int[] levels = rawInputLevels;
496         int depth = rawInputDepth;
497         if (fields == null || levels == null || depth == 0) {
498
499             /*
500              * The volatile fields are not yet set. Prepare to process the
501              * class hierarchy, storing class formats in order from the highest
502              * superclass down to the current class.
503              */

504             depth = 0;
505             int nFields = 0;
506             for (ComplexFormat format = this;
507                  format != null;
508                  format = format.getComplexSuper()) {
509                 nFields += format.getNFields();
510                 depth += 1;
511             }
512             ComplexFormat[] hierarchy = new ComplexFormat[depth];
513             int level = depth;
514             for (ComplexFormat format = this;
515                  format != null;
516                  format = format.getComplexSuper()) {
517                 level -= 1;
518                 hierarchy[level] = format;
519             }
520             assert level == 0;
521
522             /* Populate levels and fields in parallel. */
523             levels = new int[nFields];
524             fields = new FieldInfo[nFields];
525             int index = 0;
526
527             /*
528              * The primary key is the first field read/written. We use the
529              * first primary key field encountered going from this class upward
530              * in the class hierarchy.
531              */

532             if (getEntityFormat() != null) {
533                 for (level = depth - 1; level >= 0; level -= 1) {
534                     ComplexFormat format = hierarchy[level];
535                     if (format.priKeyField != null) {
536                         levels[index] = level;
537                         fields[index] = format.priKeyField;
538                         index += 1;
539                         break;
540                     }
541                 }
542                 assert index == 1;
543             }
544
545             /*
546              * Secondary key fields are read/written next, from the highest
547              * base class downward.
548              */

549             for (level = 0; level < depth; level += 1) {
550                 ComplexFormat format = hierarchy[level];
551                 for (FieldInfo field : format.secKeyFields) {
552                     levels[index] = level;
553                     fields[index] = field;
554                     index += 1;
555                 }
556             }
557
558             /*
559              * Other fields are read/written last, from the highest base class
560              * downward.
561              */

562             for (level = 0; level < depth; level += 1) {
563                 ComplexFormat format = hierarchy[level];
564                 for (FieldInfo field : format.nonKeyFields) {
565                     levels[index] = level;
566                     fields[index] = field;
567                     index += 1;
568                 }
569             }
570
571             /* We're finished -- update the volatile fields for next time. */
572             assert index == fields.length;
573             rawInputFields = fields;
574             rawInputLevels = levels;
575             rawInputDepth = depth;
576         }
577
578         /*
579          * Create an objects array that is parallel to the fields and levels
580          * arrays, but contains the RawObject for each slot from which the
581          * field value can be retrieved. The predetermined level for each
582          * field determines which RawObject in the instance hierarchy to use.
583          */

584         RawObject[] objectsByLevel = new RawObject[depth];
585         int level = depth;
586         for (RawObject raw = rawObject; raw != null; raw = raw.getSuper()) {
587             if (level == 0) {
588                 throw new IllegalArgumentException JavaDoc
589                     ("RawObject has too many superclasses: " +
590                      rawObject.getType().getClassName());
591             }
592             level -= 1;
593             objectsByLevel[level] = raw;
594         }
595         if (level > 0) {
596             throw new IllegalArgumentException JavaDoc
597                 ("RawObject has too few superclasses: " +
598                  rawObject.getType().getClassName());
599         }
600         assert level == 0;
601         RawObject[] objects = new RawObject[fields.length];
602         for (int i = 0; i < objects.length; i += 1) {
603             objects[i] = objectsByLevel[levels[i]];
604         }
605
606         /* Create the persistent object and convert all RawObject fields. */
607         EntityInput in = new RawComplexInput
608             (catalog, rawAccess, converted, fields, objects);
609         Object JavaDoc o = newInstance(in, rawAccess);
610         converted.put(rawObject, o);
611         if (getEntityFormat() != null) {
612             readPriKey(o, in, rawAccess);
613         }
614         return readObject(o, in, rawAccess);
615     }
616
617     @Override JavaDoc
618     boolean isPriKeyNullOrZero(Object JavaDoc o, boolean rawAccess) {
619         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
620         return accessor.isPriKeyFieldNullOrZero(o);
621     }
622
623     @Override JavaDoc
624     void writePriKey(Object JavaDoc o, EntityOutput output, boolean rawAccess) {
625         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
626         accessor.writePriKeyField(o, output);
627     }
628
629     @Override JavaDoc
630     public void readPriKey(Object JavaDoc o, EntityInput input, boolean rawAccess) {
631         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
632         accessor.readPriKeyField(o, input);
633     }
634
635     @Override JavaDoc
636     boolean nullifySecKey(Catalog catalog,
637                           Object JavaDoc entity,
638                           String JavaDoc keyName,
639                           Object JavaDoc keyElement) {
640         if (secKeyAddresses == null) {
641             throw new IllegalStateException JavaDoc();
642         }
643         FieldAddress addr = secKeyAddresses.get(keyName);
644         if (addr != null) {
645             Object JavaDoc oldVal = rawAccessor.getField
646                 (entity, addr.fieldNum, addr.superLevel, addr.isSecField);
647             if (oldVal != null) {
648                 if (keyElement != null) {
649                     RawObject container = (RawObject) oldVal;
650                     Object JavaDoc[] a1 = container.getElements();
651                     boolean isArray = (a1 != null);
652                     if (!isArray) {
653                         a1 = CollectionProxy.getElements(container);
654                     }
655                     if (a1 != null) {
656                         for (int i = 0; i < a1.length; i += 1) {
657                             if (keyElement.equals(a1[i])) {
658                                 int len = a1.length - 1;
659                                 Object JavaDoc[] a2 = new Object JavaDoc[len];
660                                 System.arraycopy(a1, 0, a2, 0, i);
661                                 System.arraycopy(a1, i + 1, a2, i, len - i);
662                                 if (isArray) {
663                                     rawAccessor.setField
664                                         (entity, addr.fieldNum,
665                                          addr.superLevel, addr.isSecField,
666                                          new RawObject
667                                             (container.getType(), a2));
668                                 } else {
669                                     CollectionProxy.setElements(container, a2);
670                                 }
671                                 return true;
672                             }
673                         }
674                     }
675                     return false;
676                 } else {
677                     rawAccessor.setField
678                         (entity, addr.fieldNum, addr.superLevel,
679                          addr.isSecField, null);
680                     return true;
681                 }
682             } else {
683                 return false;
684             }
685         } else {
686             return false;
687         }
688     }
689
690     @Override JavaDoc
691     void skipContents(RecordInput input) {
692         skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
693         skipToNonKeyField(input, Accessor.MAX_FIELD_NUM);
694     }
695
696     @Override JavaDoc
697     void copySecMultiKey(RecordInput input, Format keyFormat, Set JavaDoc results) {
698         CollectionProxy.copyElements(input, this, keyFormat, results);
699     }
700
701     @Override JavaDoc
702     Format skipToSecKey(RecordInput input, String JavaDoc keyName) {
703         if (secKeyAddresses == null) {
704             throw new IllegalStateException JavaDoc();
705         }
706         FieldAddress addr = secKeyAddresses.get(keyName);
707         if (addr != null) {
708             if (addr.isSecField) {
709                 addr.clsFormat.skipToSecKeyField(input, addr.fieldNum);
710             } else {
711                 skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
712                 addr.clsFormat.skipToNonKeyField(input, addr.fieldNum);
713             }
714             return addr.keyFormat;
715         } else {
716             return null;
717         }
718     }
719
720     private int getNFields() {
721         return ((priKeyField != null) ? 1 : 0) +
722                secKeyFields.size() +
723                nonKeyFields.size();
724     }
725     
726     private void skipToSecKeyField(RecordInput input, int toFieldNum) {
727         ComplexFormat superFormat = getComplexSuper();
728         if (superFormat != null) {
729             superFormat.skipToSecKeyField(input, Accessor.MAX_FIELD_NUM);
730         }
731         int maxNum = Math.min(secKeyFields.size(), toFieldNum);
732         for (int i = 0; i < maxNum; i += 1) {
733             input.skipField(secKeyFields.get(i).getType());
734         }
735     }
736     
737     private void skipToNonKeyField(RecordInput input, int toFieldNum) {
738         ComplexFormat superFormat = getComplexSuper();
739         if (superFormat != null) {
740             superFormat.skipToNonKeyField(input, Accessor.MAX_FIELD_NUM);
741         }
742         int maxNum = Math.min(nonKeyFields.size(), toFieldNum);
743         for (int i = 0; i < maxNum; i += 1) {
744             input.skipField(nonKeyFields.get(i).getType());
745         }
746     }
747
748     private static class FieldAddress {
749
750         boolean isSecField;
751         int fieldNum;
752         int superLevel;
753         ComplexFormat clsFormat;
754         Format keyFormat;
755
756         FieldAddress(boolean isSecField,
757                      int fieldNum,
758                      int superLevel,
759                      ComplexFormat clsFormat,
760                      Format keyFormat) {
761             this.isSecField = isSecField;
762             this.fieldNum = fieldNum;
763             this.superLevel = superLevel;
764             this.clsFormat = clsFormat;
765             this.keyFormat = keyFormat;
766         }
767     }
768
769     @Override JavaDoc
770     boolean evolve(Format newFormatParam, Evolver evolver) {
771
772         /* Disallow evolution to a non-complex format. */
773         if (!(newFormatParam instanceof ComplexFormat)) {
774             evolver.addMissingMutation
775                 (this, newFormatParam,
776                  "Converter is required when a complex type is changed " +
777                  "to a simple type or enum type");
778             return false;
779         }
780         ComplexFormat newFormat = (ComplexFormat) newFormatParam;
781         Mutations mutations = evolver.getMutations();
782         boolean thisChanged = false;
783         boolean superChanged = false;
784         Map JavaDoc<String JavaDoc,String JavaDoc> allKeyNameMap = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
785
786         /*
787          * Evolve all superclass formats, even when a deleted class appears in
788          * the hierarchy. This ensures that the super format's
789          * getLatestVersion/getComplexLatest method can be used accurately
790          * below.
791          */

792         for (ComplexFormat oldSuper = getComplexSuper();
793              oldSuper != null;
794              oldSuper = oldSuper.getComplexSuper()) {
795             Converter converter = mutations.getConverter
796                 (oldSuper.getClassName(), oldSuper.getVersion(), null);
797             if (converter != null) {
798                 evolver.addMissingMutation
799                     (this, newFormatParam,
800                      "Converter is required for this subclass when a " +
801                      "Converter appears on its superclass: " + converter);
802                 return false;
803             }
804             if (!evolver.evolveFormat(oldSuper)) {
805                 return false;
806             }
807             if (!oldSuper.isCurrentVersion()) {
808                 if (oldSuper.isDeleted()) {
809                     if (!oldSuper.evolveDeletedClass(evolver)) {
810                         return false;
811                     }
812                 }
813                 if (oldSuper.oldToNewKeyMap != null) {
814                     allKeyNameMap.putAll(oldSuper.oldToNewKeyMap);
815                 }
816                 superChanged = true;
817             }
818         }
819
820         /*
821          * Compare the old and new class hierarhies and decide whether each
822          * change is allowed or not:
823          * + Old deleted and removed superclass -- allowed
824          * + Old empty and removed superclass -- allowed
825          * + Old non-empty and removed superclass -- not allowed
826          * + Old superclass repositioned in the hierarchy -- not allowed
827          * + New inserted superclass -- allowed
828          */

829         Class JavaDoc newFormatCls = newFormat.getExistingType();
830         Class JavaDoc newSuper = newFormatCls;
831         List JavaDoc<Integer JavaDoc> newLevels = new ArrayList JavaDoc<Integer JavaDoc>();
832         int newLevel = 0;
833         newLevels.add(newLevel);
834
835         /*
836          * When this format has a new superclass, we treat it as a change to
837          * this format as well as to the superclass hierarchy.
838          */

839         if (getSuperFormat() == null) {
840             if (newFormatCls.getSuperclass() != Object JavaDoc.class) {
841                 thisChanged = true;
842                 superChanged = true;
843             }
844         } else {
845             if (!getSuperFormat().getLatestVersion().getClassName().equals
846                     (newFormatCls.getSuperclass().getName())) {
847                 thisChanged = true;
848                 superChanged = true;
849             }
850         }
851
852         for (ComplexFormat oldSuper = getComplexSuper();
853              oldSuper != null;
854              oldSuper = oldSuper.getComplexSuper()) {
855             
856             /* Find the matching superclass in the new hierarchy. */
857             String JavaDoc oldSuperName = oldSuper.getLatestVersion().getClassName();
858             Class JavaDoc foundNewSuper = null;
859             int tryNewLevel = newLevel;
860             for (Class JavaDoc newSuper2 = newSuper.getSuperclass();
861                  newSuper2 != Object JavaDoc.class;
862                  newSuper2 = newSuper2.getSuperclass()) {
863                 tryNewLevel += 1;
864                 if (oldSuperName.equals(newSuper2.getName())) {
865                     foundNewSuper = newSuper2;
866                     newLevel = tryNewLevel;
867                     break;
868                 }
869             }
870
871             if (foundNewSuper != null) {
872
873                 /*
874                  * We found the old superclass in the new hierarchy. Traverse
875                  * through the superclass formats that were skipped over above
876                  * when finding it.
877                  */

878                 for (Class JavaDoc newSuper2 = newSuper.getSuperclass();
879                      newSuper2 != foundNewSuper;
880                      newSuper2 = newSuper2.getSuperclass()) {
881
882                     /*
883                      * The class hierarchy changed -- a new class was inserted.
884                      */

885                     superChanged = true;
886
887                     /*
888                      * Check that the new formats skipped over above are not at
889                      * a different position in the old hierarchy.
890                      */

891                     for (ComplexFormat oldSuper2 = oldSuper.getComplexSuper();
892                          oldSuper2 != null;
893                          oldSuper2 = oldSuper2.getComplexSuper()) {
894                         String JavaDoc oldSuper2Name =
895                             oldSuper2.getLatestVersion().getClassName();
896                         if (oldSuper2Name.equals(newSuper2.getName())) {
897                             evolver.addMissingMutation
898                                 (this, newFormatParam,
899                                  "Class Converter is required when a " +
900                                  "superclass is moved in the class " +
901                                  "hierarchy: " + newSuper2.getName());
902                             return false;
903                         }
904                     }
905                 }
906                 newSuper = foundNewSuper;
907                 newLevels.add(newLevel);
908             } else {
909
910                 /*
911                  * We did not find the old superclass in the new hierarchy.
912                  * The class hierarchy changed, since an old class no longer
913                  * appears.
914                  */

915                 superChanged = true;
916
917                 /* Check that the old class can be safely removed. */
918                 if (!oldSuper.isDeleted()) {
919                     ComplexFormat oldSuperLatest =
920                         oldSuper.getComplexLatest();
921                     if (oldSuperLatest.getNFields() != 0) {
922                         evolver.addMissingMutation
923                             (this, newFormatParam,
924                              "When a superclass is removed from the class " +
925                              "hierarchy, the superclass or all of its " +
926                              "persistent fields must be deleted with a " +
927                              "Deleter: " +
928                              oldSuperLatest.getClassName());
929                         return false;
930                     }
931                 }
932
933                 if (isEntity() && isCurrentVersion()) {
934                     Map JavaDoc<String JavaDoc,SecondaryKeyMetadata> secKeys =
935                         oldSuper.clsMeta.getSecondaryKeys();
936                     for (FieldInfo field : oldSuper.secKeyFields) {
937                         SecondaryKeyMetadata meta =
938                             secKeys.get(field.getName());
939                         assert meta != null;
940                         allKeyNameMap.put(meta.getKeyName(), null);
941                     }
942                 }
943
944                 /*
945                  * Add the DO_NOT_READ_ACCESSOR level to prevent an empty class
946                  * (no persistent fields) from being read via the Accessor.
947                  */

948                 newLevels.add(EvolveReader.DO_NOT_READ_ACCESSOR);
949             }
950         }
951
952         /* Make FieldReaders for this format if needed. */
953         int result = evolveAllFields(newFormat, evolver);
954         if (result == Evolver.EVOLVE_FAILURE) {
955             return false;
956         }
957         if (result == Evolver.EVOLVE_NEEDED) {
958             thisChanged = true;
959         }
960         if (oldToNewKeyMap != null) {
961             allKeyNameMap.putAll(oldToNewKeyMap);
962         }
963
964         /* Require new version number if this class was changed. */
965         if (thisChanged &&
966             !evolver.checkUpdatedVersion
967                 ("Changes to the fields or superclass were detected", this,
968                  newFormat)) {
969             return false;
970         }
971
972         /* Rename the secondary databases. */
973         if (allKeyNameMap.size() > 0 && isEntity() && isCurrentVersion()) {
974             for (Map.Entry JavaDoc<String JavaDoc,String JavaDoc> entry : allKeyNameMap.entrySet()) {
975                  String JavaDoc oldKeyName = entry.getKey();
976                  String JavaDoc newKeyName = entry.getValue();
977                 if (newKeyName != null) {
978                     evolver.renameSecondaryDatabase
979                         (this, newFormat, oldKeyName, newKeyName);
980                 } else {
981                     evolver.deleteSecondaryDatabase(this, oldKeyName);
982                 }
983             }
984         }
985
986         /* Use an EvolveReader if needed. */
987         if (superChanged || thisChanged) {
988             Reader reader = new EvolveReader(newLevels);
989             evolver.useEvolvedFormat(this, reader, newFormat);
990         } else {
991             evolver.useOldFormat(this, newFormat);
992         }
993         return true;
994     }
995
996     @Override JavaDoc
997     boolean evolveMetadata(Format newFormatParam,
998                            Converter converter,
999                            Evolver evolver) {
1000        assert !isDeleted();
1001        assert isEntity();
1002        assert newFormatParam.isEntity();
1003        ComplexFormat newFormat = (ComplexFormat) newFormatParam;
1004
1005        if (!checkKeyTypeChange
1006                (newFormat, entityMeta.getPrimaryKey(),
1007                 newFormat.entityMeta.getPrimaryKey(), "primary key",
1008                 evolver)) {
1009            return false;
1010        }
1011
1012        Set JavaDoc<String JavaDoc> deletedKeys;
1013        if (converter instanceof EntityConverter) {
1014            EntityConverter entityConverter = (EntityConverter) converter;
1015            deletedKeys = entityConverter.getDeletedKeys();
1016        } else {
1017            deletedKeys = Collections.emptySet();
1018        }
1019
1020        Map JavaDoc<String JavaDoc,SecondaryKeyMetadata> oldSecondaryKeys =
1021            entityMeta.getSecondaryKeys();
1022        Map JavaDoc<String JavaDoc,SecondaryKeyMetadata> newSecondaryKeys =
1023            newFormat.entityMeta.getSecondaryKeys();
1024        Set JavaDoc<String JavaDoc> insertedKeys =
1025            new HashSet JavaDoc<String JavaDoc>(newSecondaryKeys.keySet());
1026
1027        for (SecondaryKeyMetadata oldMeta : oldSecondaryKeys.values()) {
1028            String JavaDoc keyName = oldMeta.getKeyName();
1029            if (deletedKeys.contains(keyName)) {
1030                if (isCurrentVersion()) {
1031                    evolver.deleteSecondaryDatabase(this, keyName);
1032                }
1033            } else {
1034                SecondaryKeyMetadata newMeta = newSecondaryKeys.get(keyName);
1035                if (newMeta == null) {
1036                    evolver.addInvalidMutation
1037                        (this, newFormat, converter,
1038                         "Existing key not found in new entity metadata: " +
1039                          keyName);
1040                    return false;
1041                }
1042                insertedKeys.remove(keyName);
1043                String JavaDoc keyLabel = "secondary key: " + keyName;
1044                if (!checkKeyTypeChange
1045                        (newFormat, oldMeta, newMeta, keyLabel, evolver)) {
1046                    return false;
1047                }
1048                if (!checkSecKeyMetadata
1049                        (newFormat, oldMeta, newMeta, evolver)) {
1050                    return false;
1051                }
1052            }
1053        }
1054
1055        if (!insertedKeys.isEmpty()) {
1056            evolver.addEvolveError
1057                (this, newFormat, "Error",
1058                 "New keys " + insertedKeys +
1059                 " not allowed when using a Converter with an entity class");
1060        }
1061
1062        return true;
1063    }
1064    
1065    /**
1066     * Checks that changes to secondary key metadata are legal.
1067     */

1068    private boolean checkSecKeyMetadata(Format newFormat,
1069                                        SecondaryKeyMetadata oldMeta,
1070                                        SecondaryKeyMetadata newMeta,
1071                                        Evolver evolver) {
1072        if (oldMeta.getRelationship() != newMeta.getRelationship()) {
1073            evolver.addEvolveError
1074                (this, newFormat,
1075                 "Change detected in the relate attribute (Relationship) " +
1076                 "of a secondary key",
1077                 "Old key: " + oldMeta.getKeyName() +
1078                 " relate: " + oldMeta.getRelationship() +
1079                 " new key: " + newMeta.getKeyName() +
1080                 " relate: " + newMeta.getRelationship());
1081            return false;
1082        }
1083        return true;
1084    }
1085    
1086    /**
1087     * Checks that the type of a key field did not change, as known from
1088     * metadata when a class conversion is used.
1089     */

1090    private boolean checkKeyTypeChange(Format newFormat,
1091                                       FieldMetadata oldMeta,
1092                                       FieldMetadata newMeta,
1093                                       String JavaDoc keyLabel,
1094                                       Evolver evolver) {
1095        String JavaDoc oldClass = oldMeta.getClassName();
1096        String JavaDoc newClass = newMeta.getClassName();
1097        if (!oldClass.equals(newClass)) {
1098            SimpleCatalog catalog = SimpleCatalog.getInstance();
1099            Format oldType = catalog.getFormat(oldClass);
1100            Format newType = catalog.getFormat(newClass);
1101            if (oldType == null || newType == null ||
1102                ((oldType.getWrapperFormat() == null ||
1103                  oldType.getWrapperFormat().getId() !=
1104                  newType.getId()) &&
1105                 (newType.getWrapperFormat() == null ||
1106                  newType.getWrapperFormat().getId() !=
1107                  oldType.getId()))) {
1108                evolver.addEvolveError
1109                    (this, newFormat,
1110                     "Type change detected for " + keyLabel,
1111                     "Old field type: " + oldClass +
1112                     " is not compatible with the new type: " +
1113                     newClass +
1114                     " old field: " + oldMeta.getName() +
1115                     " new field: " + newMeta.getName());
1116                return false;
1117            }
1118        }
1119        return true;
1120    }
1121
1122    /**
1123     * Special case for creating FieldReaders for a deleted class when it
1124     * appears in the class hierarchy of its non-deleted subclass.
1125     */

1126    private boolean evolveDeletedClass(Evolver evolver) {
1127        assert isDeleted();
1128        if (secKeyFieldReader == null || nonKeyFieldReader == null) {
1129            if (priKeyField != null &&
1130                getEntityFormat() != null &&
1131                !getEntityFormat().isDeleted()) {
1132                evolver.addEvolveError
1133                    (this, this,
1134                     "Class containing primary key field was deleted ",
1135                     "Primary key is needed in an entity class hierarchy: " +
1136                     priKeyField.getName());
1137                return false;
1138            } else {
1139                secKeyFieldReader = new SkipFieldReader(0, secKeyFields);
1140                nonKeyFieldReader = new SkipFieldReader(0, nonKeyFields);
1141                return true;
1142            }
1143        } else {
1144            return true;
1145        }
1146    }
1147
1148    /**
1149     * Creates a FieldReader for secondary key fields and non-key fields if
1150     * necessary. Checks the primary key field if necessary. Does not evolve
1151     * superclass format fields.
1152     */

1153    private int evolveAllFields(ComplexFormat newFormat, Evolver evolver) {
1154
1155        assert !isDeleted();
1156        secKeyFieldReader = null;
1157        nonKeyFieldReader = null;
1158        oldToNewKeyMap = null;
1159
1160        /* Evolve primary key field. */
1161        boolean evolveFailure = false;
1162        boolean evolveNeeded = false;
1163        if (priKeyField != null) {
1164            int result = evolver.evolveRequiredKeyField
1165                (this, newFormat, priKeyField, newFormat.priKeyField);
1166            if (result == Evolver.EVOLVE_FAILURE) {
1167                evolveFailure = true;
1168            } else if (result == Evolver.EVOLVE_NEEDED) {
1169                evolveNeeded = true;
1170            }
1171        }
1172
1173        /* Evolve secondary key fields. */
1174        FieldReader reader = evolveFieldList
1175            (secKeyFields, newFormat.secKeyFields, true,
1176             newFormat.nonKeyFields, newFormat, evolver);
1177        if (reader == FieldReader.EVOLVE_FAILURE) {
1178            evolveFailure = true;
1179        } else if (reader != null) {
1180            evolveNeeded = true;
1181        }
1182        if (reader != FieldReader.EVOLVE_NEEDED) {
1183            secKeyFieldReader = reader;
1184        }
1185
1186        /* Evolve non-key fields. */
1187        reader = evolveFieldList
1188            (nonKeyFields, newFormat.nonKeyFields, false,
1189             newFormat.secKeyFields, newFormat, evolver);
1190        if (reader == FieldReader.EVOLVE_FAILURE) {
1191            evolveFailure = true;
1192        } else if (reader != null) {
1193            evolveNeeded = true;
1194        }
1195        if (reader != FieldReader.EVOLVE_NEEDED) {
1196            nonKeyFieldReader = reader;
1197        }
1198
1199        /* Return result. */
1200        if (evolveFailure) {
1201            return Evolver.EVOLVE_FAILURE;
1202        } else if (evolveNeeded) {
1203            return Evolver.EVOLVE_NEEDED;
1204        } else {
1205            return Evolver.EVOLVE_NONE;
1206        }
1207    }
1208
1209    /**
1210     * Evolves a list of fields, either secondary key or non-key fields, for a
1211     * single class format.
1212     *
1213     * @return a FieldReader if field evolution is needed, null if no evolution
1214     * is needed, or FieldReader.EVOLVE_FAILURE if an evolution error occurs.
1215     */

1216    private FieldReader evolveFieldList(List JavaDoc<FieldInfo> oldFields,
1217                                        List JavaDoc<FieldInfo> newFields,
1218                                        boolean isOldSecKeyField,
1219                                        List JavaDoc<FieldInfo> otherNewFields,
1220                                        ComplexFormat newFormat,
1221                                        Evolver evolver) {
1222        Mutations mutations = evolver.getMutations();
1223        boolean evolveFailure = false;
1224        boolean evolveNeeded = false;
1225        boolean readerNeeded = false;
1226        List JavaDoc<FieldReader> fieldReaders = new ArrayList JavaDoc<FieldReader>();
1227        FieldReader currentReader = null;
1228        int prevNewFieldIndex = newFields.size();
1229        int newFieldsMatched = 0;
1230
1231        /*
1232         * Add FieldReaders to the list in old field storage order, since that
1233         * is the order in which field values must be read.
1234         */

1235        fieldLoop:
1236        for (int oldFieldIndex = 0;
1237             oldFieldIndex < oldFields.size();
1238             oldFieldIndex += 1) {
1239
1240            FieldInfo oldField = oldFields.get(oldFieldIndex);
1241            String JavaDoc oldName = oldField.getName();
1242            SecondaryKeyMetadata oldMeta = null;
1243            if (isOldSecKeyField) {
1244                oldMeta = clsMeta.getSecondaryKeys().get(oldName);
1245                assert oldMeta != null;
1246            }
1247
1248            /* Get field mutations. */
1249            Renamer renamer = mutations.getRenamer
1250                (getClassName(), getVersion(), oldName);
1251            Deleter deleter = mutations.getDeleter
1252                (getClassName(), getVersion(), oldName);
1253            Converter converter = mutations.getConverter
1254                (getClassName(), getVersion(), oldName);
1255            if (deleter != null && (converter != null || renamer != null)) {
1256                evolver.addInvalidMutation
1257                    (this, newFormat, deleter,
1258                     "Field Deleter is not allowed along with a Renamer or " +
1259                     "Converter for the same field: " + oldName);
1260                evolveFailure = true;
1261                continue fieldLoop;
1262            }
1263
1264            /*
1265             * Match old and new field by name, taking into account the Renamer
1266             * mutation. If the @SecondaryKey annotation was added or removed,
1267             * the field will have moved from one of the two field lists to the
1268             * other.
1269             */

1270            String JavaDoc newName = (renamer != null) ?
1271                renamer.getNewName() : oldName;
1272            if (!oldName.equals(newName)) {
1273                if (newToOldFieldMap == null) {
1274                    newToOldFieldMap = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
1275                }
1276                newToOldFieldMap.put(newName, oldName);
1277            }
1278            int newFieldIndex = FieldInfo.getFieldIndex(newFields, newName);
1279            FieldInfo newField = null;
1280            boolean isNewSecKeyField = isOldSecKeyField;
1281            if (newFieldIndex >= 0) {
1282                newField = newFields.get(newFieldIndex);
1283            } else {
1284                newFieldIndex = FieldInfo.getFieldIndex
1285                    (otherNewFields, newName);
1286                if (newFieldIndex >= 0) {
1287                    newField = otherNewFields.get(newFieldIndex);
1288                    isNewSecKeyField = !isOldSecKeyField;
1289                }
1290                evolveNeeded = true;
1291                readerNeeded = true;
1292            }
1293
1294            /* Apply field Deleter and continue. */
1295            if (deleter != null) {
1296                if (newField != null) {
1297                    evolver.addInvalidMutation
1298                        (this, newFormat, deleter,
1299                         "Field Deleter is not allowed when the persistent " +
1300                         "field is still present: " + oldName);
1301                    evolveFailure = true;
1302                }
1303                /* A SkipFieldReader can read multiple sequential fields. */
1304                if (currentReader instanceof SkipFieldReader &&
1305                    currentReader.acceptField
1306                        (oldFieldIndex, newFieldIndex, isNewSecKeyField)) {
1307                    currentReader.addField(oldField);
1308                } else {
1309                    currentReader = new SkipFieldReader
1310                        (oldFieldIndex, oldField);
1311                    fieldReaders.add(currentReader);
1312                    readerNeeded = true;
1313                    evolveNeeded = true;
1314                }
1315                if (isOldSecKeyField) {
1316                    if (oldToNewKeyMap == null) {
1317                        oldToNewKeyMap = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
1318                    }
1319                    oldToNewKeyMap.put(oldMeta.getKeyName(), null);
1320                }
1321                continue fieldLoop;
1322            } else {
1323                if (newField == null) {
1324                    evolver.addMissingMutation
1325                        (this, newFormat,
1326                         "Field is not present or not persistent: " +
1327                         oldName);
1328                    evolveFailure = true;
1329                    continue fieldLoop;
1330                }
1331            }
1332
1333            /*
1334             * The old field corresponds to a known new field, and no Deleter
1335             * mutation applies.
1336             */

1337            newFieldsMatched += 1;
1338
1339            /* Get and process secondary key metadata changes. */
1340            SecondaryKeyMetadata newMeta = null;
1341            if (isOldSecKeyField && isNewSecKeyField) {
1342                newMeta = newFormat.clsMeta.getSecondaryKeys().get(newName);
1343                assert newMeta != null;
1344
1345                /* Validate metadata changes. */
1346                if (!checkSecKeyMetadata
1347                        (newFormat, oldMeta, newMeta, evolver)) {
1348                    evolveFailure = true;
1349                    continue fieldLoop;
1350                }
1351
1352                /*
1353                 * Check for a renamed key and save the old-to-new mapping for
1354                 * use in renaming the secondary database and for key
1355                 * extraction.
1356                 */

1357                String JavaDoc oldKeyName = oldMeta.getKeyName();
1358                String JavaDoc newKeyName = newMeta.getKeyName();
1359                if (!oldKeyName.equals(newKeyName)) {
1360                    if (oldToNewKeyMap == null) {
1361                        oldToNewKeyMap = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
1362                    }
1363                    oldToNewKeyMap.put(oldName, newName);
1364                    evolveNeeded = true;
1365                }
1366            } else if (isOldSecKeyField && !isNewSecKeyField) {
1367                if (oldToNewKeyMap == null) {
1368                    oldToNewKeyMap = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
1369                }
1370                oldToNewKeyMap.put(oldMeta.getKeyName(), null);
1371            }
1372
1373            /* Apply field Converter and continue. */
1374            if (converter != null) {
1375                if (isOldSecKeyField) {
1376                    evolver.addInvalidMutation
1377                        (this, newFormat, converter,
1378                         "Field Converter is not allowed for secondary key " +
1379                         "fields: " + oldName);
1380                    evolveFailure = true;
1381                } else {
1382                    currentReader = new ConvertFieldReader
1383                        (converter, newFieldIndex, isNewSecKeyField);
1384                    fieldReaders.add(currentReader);
1385                    readerNeeded = true;
1386                    evolveNeeded = true;
1387                }
1388                continue fieldLoop;
1389            }
1390
1391            /*
1392             * Evolve the declared version of the field format and all versions
1393             * more recent, and the formats for all of their subclasses. While
1394             * we're at it, check to see if all possible classes are converted.
1395             */

1396            boolean allClassesConverted = true;
1397            Format oldFieldFormat = oldField.getType();
1398            for (Format formatVersion = oldFieldFormat.getLatestVersion();
1399                 true;
1400                 formatVersion = formatVersion.getPreviousVersion()) {
1401                assert formatVersion != null;
1402                if (!evolver.evolveFormat(formatVersion)) {
1403                    evolveFailure = true;
1404                    continue fieldLoop;
1405                }
1406                if (!formatVersion.isNew() &&
1407                    !evolver.isClassConverted(formatVersion)) {
1408                    allClassesConverted = false;
1409                }
1410                Set JavaDoc<Format> subclassFormats =
1411                    evolver.getSubclassFormats(formatVersion);
1412                if (subclassFormats != null) {
1413                    for (Format format2 : subclassFormats) {
1414                        if (!evolver.evolveFormat(format2)) {
1415                            evolveFailure = true;
1416                            continue fieldLoop;
1417                        }
1418                        if (!format2.isNew() &&
1419                            !evolver.isClassConverted(format2)) {
1420                            allClassesConverted = false;
1421                        }
1422                    }
1423                }
1424                if (formatVersion == oldFieldFormat) {
1425                    break;
1426                }
1427            }
1428
1429            /*
1430             * Check for compatible field types and apply a field widener if
1431             * needed. If no widener is needed, fall through and apply a
1432             * PlainFieldReader.
1433             */

1434            Format oldLatestFormat = oldFieldFormat.getLatestVersion();
1435            Format newFieldFormat = newField.getType();
1436            if (oldLatestFormat.getClassName().equals
1437                    (newFieldFormat.getClassName()) &&
1438                !oldLatestFormat.isDeleted()) {
1439                /* Formats are identical. Fall through. */
1440            } else if (allClassesConverted) {
1441                /* All old classes will be converted. Fall through. */
1442                evolveNeeded = true;
1443            } else if (WidenerInput.isWideningSupported
1444                        (oldLatestFormat, newFieldFormat, isOldSecKeyField)) {
1445                /* Apply field widener and continue. */
1446                currentReader = new WidenFieldReader
1447                    (oldLatestFormat, newFieldFormat, newFieldIndex,
1448                     isNewSecKeyField);
1449                fieldReaders.add(currentReader);
1450                readerNeeded = true;
1451                evolveNeeded = true;
1452                continue fieldLoop;
1453            } else {
1454                boolean refWidened = false;
1455                if (!newFieldFormat.isPrimitive() &&
1456                    !oldLatestFormat.isPrimitive() &&
1457                    !oldLatestFormat.isDeleted() &&
1458                    !evolver.isClassConverted(oldLatestFormat)) {
1459                    Class JavaDoc oldCls = oldLatestFormat.getExistingType();
1460                    Class JavaDoc newCls = newFieldFormat.getExistingType();
1461                    if (newCls.isAssignableFrom(oldCls)) {
1462                        refWidened = true;
1463                    }
1464                }
1465                if (refWidened) {
1466                    /* A reference type has been widened. Fall through. */
1467                    evolveNeeded = true;
1468                } else {
1469                    /* Types are not compatible. */
1470                    evolver.addMissingMutation
1471                        (this, newFormat,
1472                         "Old field type: " + oldLatestFormat.getClassName() +
1473                         " is not compatible with the new type: " +
1474                         newFieldFormat.getClassName() +
1475                         " for field: " + oldName);
1476                    evolveFailure = true;
1477                    continue fieldLoop;
1478                }
1479            }
1480
1481            /*
1482             * Old to new field conversion is not needed or is automatic. Read
1483             * fields as if no evolution is needed. A PlainFieldReader can
1484             * read multiple sequential fields.
1485             */

1486            if (currentReader instanceof PlainFieldReader &&
1487                currentReader.acceptField
1488                    (oldFieldIndex, newFieldIndex, isNewSecKeyField)) {
1489                currentReader.addField(oldField);
1490            } else {
1491                currentReader = new PlainFieldReader
1492                    (oldFieldIndex, newFieldIndex, isNewSecKeyField);
1493                fieldReaders.add(currentReader);
1494            }
1495        }
1496
1497        /* If there are new fields, there must be a new type. */
1498        if (newFieldsMatched < newFields.size()) {
1499            evolveNeeded = true;
1500            if (oldFields.size() > 0) {
1501                readerNeeded = true;
1502            }
1503        }
1504
1505        if (evolveFailure) {
1506            return FieldReader.EVOLVE_FAILURE;
1507        } else if (readerNeeded) {
1508            assert fieldReaders.size() > 0 : getClassName();
1509            if (fieldReaders.size() == 1) {
1510                return fieldReaders.get(0);
1511            } else {
1512                return new MultiFieldReader(fieldReaders);
1513            }
1514        } else if (evolveNeeded) {
1515            return FieldReader.EVOLVE_NEEDED;
1516        } else {
1517            return null;
1518        }
1519    }
1520
1521    /**
1522     * Base class for all FieldReader subclasses. A FieldReader reads one or
1523     * more fields in the old format data, and may call the new format Accessor
1524     * to set the field values.
1525     */

1526    private static abstract class FieldReader implements Serializable JavaDoc {
1527
1528        static final FieldReader EVOLVE_NEEDED =
1529            new PlainFieldReader(0, 0, false);
1530        static final FieldReader EVOLVE_FAILURE =
1531            new PlainFieldReader(0, 0, false);
1532
1533        private static final long serialVersionUID = 866041475399255164L;
1534
1535        FieldReader() {
1536        }
1537
1538        void initialize(Catalog catalog,
1539                        ComplexFormat oldParentFormat,
1540                        ComplexFormat newParentFormat,
1541                        boolean isOldSecKey) {
1542        }
1543
1544        boolean acceptField(int oldFieldIndex,
1545                            int newFieldIndex,
1546                            boolean isNewSecKeyField) {
1547            return false;
1548        }
1549
1550        void addField(FieldInfo oldField) {
1551            throw new UnsupportedOperationException JavaDoc();
1552        }
1553
1554        abstract void readFields(Object JavaDoc o,
1555                                 EntityInput input,
1556                                 Accessor accessor,
1557                                 int superLevel);
1558    }
1559
1560    /**
1561     * Reads a continguous block of fields that have the same format in the old
1562     * and new formats.
1563     */

1564    private static class PlainFieldReader extends FieldReader {
1565
1566        private static final long serialVersionUID = 1795593463439931402L;
1567
1568        private int startField;
1569        private int endField;
1570        private boolean secKeyField;
1571        private transient int endOldField;
1572
1573        PlainFieldReader(int oldFieldIndex,
1574                         int newFieldIndex,
1575                         boolean isNewSecKeyField) {
1576            endOldField = oldFieldIndex;
1577            startField = newFieldIndex;
1578            endField = newFieldIndex;
1579            secKeyField = isNewSecKeyField;
1580        }
1581
1582        @Override JavaDoc
1583        boolean acceptField(int oldFieldIndex,
1584                            int newFieldIndex,
1585                            boolean isNewSecKeyField) {
1586            return oldFieldIndex == endOldField + 1 &&
1587                   newFieldIndex == endField + 1 &&
1588                   secKeyField == isNewSecKeyField;
1589        }
1590
1591        @Override JavaDoc
1592        void addField(FieldInfo oldField) {
1593            endField += 1;
1594            endOldField += 1;
1595        }
1596
1597        @Override JavaDoc
1598        final void readFields(Object JavaDoc o,
1599                              EntityInput input,
1600                              Accessor accessor,
1601                              int superLevel) {
1602            if (secKeyField) {
1603                accessor.readSecKeyFields
1604                    (o, input, startField, endField, superLevel);
1605            } else {
1606                accessor.readNonKeyFields
1607                    (o, input, startField, endField, superLevel);
1608            }
1609        }
1610    }
1611
1612    /**
1613     * Skips a continguous block of fields that exist in the old format but not
1614     * in the new format.
1615     */

1616    private static class SkipFieldReader extends FieldReader {
1617
1618        private static final long serialVersionUID = -3060281692155253098L;
1619
1620        private List JavaDoc<Format> fieldFormats;
1621        private transient int endField;
1622
1623        SkipFieldReader(int startField, List JavaDoc<FieldInfo> fields) {
1624            endField = startField + fields.size() - 1;
1625            fieldFormats = new ArrayList JavaDoc<Format>(fields.size());
1626            for (FieldInfo field : fields) {
1627                fieldFormats.add(field.getType());
1628            }
1629        }
1630
1631        SkipFieldReader(int startField, FieldInfo oldField) {
1632            endField = startField;
1633            fieldFormats = new ArrayList JavaDoc<Format>();
1634            fieldFormats.add(oldField.getType());
1635        }
1636
1637        @Override JavaDoc
1638        boolean acceptField(int oldFieldIndex,
1639                            int newFieldIndex,
1640                            boolean isNewSecKeyField) {
1641            return oldFieldIndex == endField + 1;
1642        }
1643
1644        @Override JavaDoc
1645        void addField(FieldInfo oldField) {
1646            endField += 1;
1647            fieldFormats.add(oldField.getType());
1648        }
1649
1650        @Override JavaDoc
1651        final void readFields(Object JavaDoc o,
1652                              EntityInput input,
1653                              Accessor accessor,
1654                              int superLevel) {
1655            for (Format format : fieldFormats) {
1656                input.skipField(format);
1657            }
1658        }
1659    }
1660
1661    /**
1662     * Converts a single field using a field Converter.
1663     */

1664    private static class ConvertFieldReader extends FieldReader {
1665
1666        private static final long serialVersionUID = 8736410481633998710L;
1667
1668        private Converter converter;
1669        private int fieldNum;
1670        private boolean secKeyField;
1671        private transient Format oldFormat;
1672        private transient Format newFormat;
1673
1674        ConvertFieldReader(Converter converter,
1675                           int newFieldIndex,
1676                           boolean isNewSecKeyField) {
1677            this.converter = converter;
1678            fieldNum = newFieldIndex;
1679            secKeyField = isNewSecKeyField;
1680        }
1681
1682        @Override JavaDoc
1683        void initialize(Catalog catalog,
1684                        ComplexFormat oldParentFormat,
1685                        ComplexFormat newParentFormat,
1686                        boolean isOldSecKey) {
1687            if (isOldSecKey) {
1688                oldFormat =
1689                    oldParentFormat.secKeyFields.get(fieldNum).getType();
1690            } else {
1691                oldFormat =
1692                    oldParentFormat.nonKeyFields.get(fieldNum).getType();
1693            }
1694            if (secKeyField) {
1695                newFormat =
1696                    newParentFormat.secKeyFields.get(fieldNum).getType();
1697            } else {
1698                newFormat =
1699                    newParentFormat.nonKeyFields.get(fieldNum).getType();
1700            }
1701        }
1702
1703        @Override JavaDoc
1704        final void readFields(Object JavaDoc o,
1705                              EntityInput input,
1706                              Accessor accessor,
1707                              int superLevel) {
1708
1709            /* Create and read the old format instance in raw mode. */
1710            boolean currentRawMode = input.setRawAccess(true);
1711            Object JavaDoc value;
1712            try {
1713                if (oldFormat.isPrimitive()) {
1714                    value = input.readKeyObject(oldFormat);
1715                } else {
1716                    value = input.readObject();
1717                }
1718            } finally {
1719                input.setRawAccess(currentRawMode);
1720            }
1721
1722            /* Convert the raw instance to the current format. */
1723            Catalog catalog = input.getCatalog();
1724            value = converter.getConversion().convert(value);
1725            
1726            /* Use a RawSingleInput to convert and type-check the value. */
1727            EntityInput rawInput = new RawSingleInput
1728                (catalog, currentRawMode, null, value, newFormat);
1729
1730            if (secKeyField) {
1731                accessor.readSecKeyFields
1732                    (o, rawInput, fieldNum, fieldNum, superLevel);
1733            } else {
1734                accessor.readNonKeyFields
1735                    (o, rawInput, fieldNum, fieldNum, superLevel);
1736            }
1737        }
1738    }
1739
1740    /**
1741     * Widens a single field using a field Converter.
1742     */

1743    private static class WidenFieldReader extends FieldReader {
1744
1745        private static final long serialVersionUID = -2054520670170407282L;
1746
1747        private int fromFormatId;
1748        private int toFormatId;
1749        private int fieldNum;
1750        private boolean secKeyField;
1751
1752        WidenFieldReader(Format oldFormat,
1753                         Format newFormat,
1754                         int newFieldIndex,
1755                         boolean isNewSecKeyField) {
1756            fromFormatId = oldFormat.getId();
1757            toFormatId = newFormat.getId();
1758            fieldNum = newFieldIndex;
1759            secKeyField = isNewSecKeyField;
1760        }
1761
1762        @Override JavaDoc
1763        final void readFields(Object JavaDoc o,
1764                              EntityInput input,
1765                              Accessor accessor,
1766                              int superLevel) {
1767            
1768            /* The Accessor reads the field value from a WidenerInput. */
1769            EntityInput widenerInput = new WidenerInput
1770                (input, fromFormatId, toFormatId);
1771
1772            if (secKeyField) {
1773                accessor.readSecKeyFields
1774                    (o, widenerInput, fieldNum, fieldNum, superLevel);
1775            } else {
1776                accessor.readNonKeyFields
1777                    (o, widenerInput, fieldNum, fieldNum, superLevel);
1778            }
1779        }
1780    }
1781
1782    /**
1783     * A FieldReader composed of other FieldReaders, and that calls them in
1784     * sequence. Used when more than one FieldReader is needed for a list of
1785     * fields.
1786     */

1787    private static class MultiFieldReader extends FieldReader {
1788
1789        private static final long serialVersionUID = -6035976787562441473L;
1790
1791        private List JavaDoc<FieldReader> subReaders;
1792
1793        MultiFieldReader(List JavaDoc<FieldReader> subReaders) {
1794            this.subReaders = subReaders;
1795        }
1796
1797        @Override JavaDoc
1798        void initialize(Catalog catalog,
1799                        ComplexFormat oldParentFormat,
1800                        ComplexFormat newParentFormat,
1801                        boolean isOldSecKey) {
1802            for (FieldReader reader : subReaders) {
1803                reader.initialize
1804                    (catalog, oldParentFormat, newParentFormat, isOldSecKey);
1805            }
1806        }
1807
1808        @Override JavaDoc
1809        final void readFields(Object JavaDoc o,
1810                              EntityInput input,
1811                              Accessor accessor,
1812                              int superLevel) {
1813            for (FieldReader reader : subReaders) {
1814                reader.readFields(o, input, accessor, superLevel);
1815            }
1816        }
1817    }
1818
1819    /**
1820     * The Reader for evolving ComplexFormat instances. Reads the old format
1821     * data one class (one level in the class hierarchy) at a time. If an
1822     * Accessor is used at a given level, the Accessor is used for the
1823     * corresponding level in the new class hierarchy (classes may be
1824     * inserted/deleted during evolution). At each level, a FieldReader is
1825     * called to evolve the secondary key and non-key lists of fields.
1826     */

1827    private static class EvolveReader implements Reader {
1828
1829        static final int DO_NOT_READ_ACCESSOR = Integer.MAX_VALUE;
1830
1831        private static final long serialVersionUID = -1016140948306913283L;
1832
1833        private transient ComplexFormat newFormat;
1834
1835        /**
1836         * oldHierarchy contains the formats of the old class hierarchy in most
1837         * to least derived class order.
1838         */

1839        private transient ComplexFormat[] oldHierarchy;
1840
1841        /**
1842         * newHierarchyLevels contains the corresponding level in the new
1843         * hierarchy for each format in oldHierarchy. newHierarchyLevels is
1844         * indexed by the oldHierarchy index.
1845         */

1846        private int[] newHierarchyLevels;
1847
1848        EvolveReader(List JavaDoc<Integer JavaDoc> newHierarchyLevelsList) {
1849            int oldDepth = newHierarchyLevelsList.size();
1850            newHierarchyLevels = new int[oldDepth];
1851            newHierarchyLevelsList.toArray();
1852            for (int i = 0; i < oldDepth; i += 1) {
1853                newHierarchyLevels[i] = newHierarchyLevelsList.get(i);
1854            }
1855        }
1856
1857        public void initializeReader(Catalog catalog, Format oldFormatParam) {
1858
1859            ComplexFormat oldFormat = (ComplexFormat) oldFormatParam;
1860            newFormat = oldFormat.getComplexLatest();
1861            newFormat.initializeIfNeeded(catalog);
1862
1863            /* Create newHierarchy array. */
1864            int newDepth = 0;
1865            for (Format format = newFormat;
1866                 format != null;
1867                 format = format.getSuperFormat()) {
1868                newDepth += 1;
1869            }
1870            ComplexFormat[] newHierarchy = new ComplexFormat[newDepth];
1871            int level = 0;
1872            for (ComplexFormat format = newFormat;
1873                 format != null;
1874                 format = format.getComplexSuper()) {
1875                newHierarchy[level] = format;
1876                level += 1;
1877            }
1878            assert level == newDepth;
1879
1880            /* Create oldHierarchy array and initialize FieldReaders. */
1881            int oldDepth = newHierarchyLevels.length;
1882            oldHierarchy = new ComplexFormat[oldDepth];
1883            level = 0;
1884            for (ComplexFormat oldFormat2 = oldFormat;
1885                 oldFormat2 != null;
1886                 oldFormat2 = oldFormat2.getComplexSuper()) {
1887                oldHierarchy[level] = oldFormat2;
1888                int level2 = newHierarchyLevels[level];
1889                ComplexFormat newFormat2 = (level2 != DO_NOT_READ_ACCESSOR) ?
1890                    newHierarchy[level2] : null;
1891                level += 1;
1892                if (oldFormat2.secKeyFieldReader != null) {
1893                    oldFormat2.secKeyFieldReader.initialize
1894                        (catalog, oldFormat2, newFormat2, true);
1895                }
1896                if (oldFormat2.nonKeyFieldReader != null) {
1897                    oldFormat2.nonKeyFieldReader.initialize
1898                        (catalog, oldFormat2, newFormat2, false);
1899                }
1900            }
1901            assert level == oldDepth;
1902        }
1903
1904        public Object JavaDoc newInstance(EntityInput input, boolean rawAccess) {
1905            return newFormat.newInstance(input, rawAccess);
1906        }
1907
1908        public void readPriKey(Object JavaDoc o,
1909                               EntityInput input,
1910                               boolean rawAccess) {
1911            /* No conversion necessary for primary keys. */
1912            newFormat.readPriKey(o, input, rawAccess);
1913        }
1914
1915        public Object JavaDoc readObject(Object JavaDoc o,
1916                                 EntityInput input,
1917                                 boolean rawAccess) {
1918
1919            /* Use the Accessor for the new format. */
1920            Accessor accessor = rawAccess ? newFormat.rawAccessor
1921                                          : newFormat.objAccessor;
1922
1923            /* Read old format fields from the top-most class downward. */
1924            int maxMinusOne = oldHierarchy.length - 1;
1925
1926            /* Read secondary key fields with the adjusted superclass level. */
1927            for (int i = maxMinusOne; i >= 0; i -= 1) {
1928                FieldReader reader = oldHierarchy[i].secKeyFieldReader;
1929                int newLevel = newHierarchyLevels[i];
1930                if (reader != null) {
1931                    reader.readFields(o, input, accessor, newLevel);
1932                } else if (newLevel != DO_NOT_READ_ACCESSOR) {
1933                    accessor.readSecKeyFields
1934                        (o, input, 0, Accessor.MAX_FIELD_NUM, newLevel);
1935                }
1936            }
1937
1938            /* Read non-key fields with the adjusted superclass level. */
1939            for (int i = maxMinusOne; i >= 0; i -= 1) {
1940                FieldReader reader = oldHierarchy[i].nonKeyFieldReader;
1941                int newLevel = newHierarchyLevels[i];
1942                if (reader != null) {
1943                    reader.readFields(o, input, accessor, newLevel);
1944                } else if (newLevel != DO_NOT_READ_ACCESSOR) {
1945                    accessor.readNonKeyFields
1946                        (o, input, 0, Accessor.MAX_FIELD_NUM, newLevel);
1947                }
1948            }
1949            return o;
1950        }
1951    }
1952}
1953
Popular Tags