KickJava   Java API By Example, From Geeks To Geeks.

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


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

8
9 package com.sleepycat.persist.impl;
10
11 import java.util.ArrayList JavaDoc;
12 import java.util.Arrays JavaDoc;
13 import java.util.HashMap JavaDoc;
14 import java.util.IdentityHashMap JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import com.sleepycat.persist.model.ClassMetadata;
19 import com.sleepycat.persist.model.FieldMetadata;
20 import com.sleepycat.persist.raw.RawField;
21 import com.sleepycat.persist.raw.RawObject;
22
23 /**
24  * Format for a composite key class.
25  *
26  * This class is similar to ComplexFormat in that a composite key class and
27  * other complex classes have fields, and the Accessor interface is used to
28  * access those fields. Composite key classes are different in the following
29  * ways:
30  *
31  * - The superclass must be Object. No inheritance is allowed.
32  *
33  * - All instance fields must be annotated with @KeyField, which determines
34  * their order in the data bytes.
35  *
36  * - Although fields may be reference types (primitive wrappers or other simple
37  * reference types), they are stored as if they were primitives. No object
38  * format ID is stored, and the class of the object must be the declared
39  * classs of the field; i.e., no polymorphism is allowed for key fields.
40  * In other words, a composite key is stored as an ordinary tuple as defined
41  * in the com.sleepycat.bind.tuple package. This keeps the key small and
42  * gives it a well defined sort order.
43  *
44  * - If the key class implements Comparable, it is called by the Database
45  * btree comparator. It must therefore be available during JE recovery,
46  * before the store and catalog have been opened. To support this, this
47  * format can be constructed during recovery. A SimpleCatalog singleton
48  * instance is used to provide a catalog of simple types that is used by
49  * the composite key format.
50  *
51  * - When interacting with the Accessor, the composite key format treats the
52  * Accessor's non-key fields as its key fields. The Accessor's key fields
53  * are secondary keys, while the composite format's key fields are the
54  * component parts of a single key.
55  *
56  * @author Mark Hayes
57  */

58 public class CompositeKeyFormat extends Format {
59
60     private static final long serialVersionUID = 306843428409314630L;
61
62     private ClassMetadata metadata;
63     private List JavaDoc<FieldInfo> fields;
64     private transient Accessor objAccessor;
65     private transient Accessor rawAccessor;
66     private transient volatile Map JavaDoc<String JavaDoc,RawField> rawFields;
67     private transient volatile FieldInfo[] rawInputFields;
68
69     static String JavaDoc[] getFieldNameArray(List JavaDoc<FieldMetadata> list) {
70         int index = 0;
71         String JavaDoc[] a = new String JavaDoc[list.size()];
72         for (FieldMetadata f : list) {
73             a[index] = f.getName();
74             index += 1;
75         }
76         return a;
77     }
78
79     CompositeKeyFormat(Class JavaDoc cls,
80                        ClassMetadata metadata,
81                        List JavaDoc<FieldMetadata> fieldNames) {
82         this(cls, metadata, getFieldNameArray(fieldNames));
83     }
84
85     CompositeKeyFormat(Class JavaDoc cls,
86                        ClassMetadata metadata,
87                        String JavaDoc[] fieldNames) {
88         super(cls);
89         this.metadata = metadata;
90
91         /* Check that the superclass is Object. */
92         Class JavaDoc superCls = cls.getSuperclass();
93         if (superCls != Object JavaDoc.class) {
94             throw new IllegalArgumentException JavaDoc
95                 ("Composite key class must be derived from Object: " +
96                  cls.getName());
97         }
98
99         /* Populate fields list in fieldNames order. */
100         List JavaDoc<FieldInfo> instanceFields = FieldInfo.getInstanceFields(cls);
101         fields = new ArrayList JavaDoc<FieldInfo>(instanceFields.size());
102         for (String JavaDoc fieldName : fieldNames) {
103             FieldInfo field = null;
104             for (FieldInfo tryField : instanceFields) {
105                 if (fieldName.equals(tryField.getName())) {
106                     field = tryField;
107                     break;
108                 }
109             }
110             if (field == null) {
111                 throw new IllegalArgumentException JavaDoc
112                     ("Composite key field is not an instance field:" +
113                      getClassName() + '.' + fieldName);
114             }
115             fields.add(field);
116             instanceFields.remove(field);
117             if (!SimpleCatalog.isSimpleType(field.getFieldClass())) {
118                 throw new IllegalArgumentException JavaDoc
119                     ("Composite key field is not a simple type: " +
120                      getClassName() + '.' + fieldName);
121             }
122         }
123         if (instanceFields.size() > 0) {
124             throw new IllegalArgumentException JavaDoc
125                 ("All composite key instance fields must be key fields: " +
126                  getClassName() + '.' + instanceFields.get(0).getName());
127         }
128     }
129
130     @Override JavaDoc
131     void migrateFromBeta(Map JavaDoc<String JavaDoc,Format> formatMap) {
132         super.migrateFromBeta(formatMap);
133         for (FieldInfo field : fields) {
134             field.migrateFromBeta(formatMap);
135         }
136     }
137
138     @Override JavaDoc
139     boolean isModelClass() {
140         return true;
141     }
142
143     @Override JavaDoc
144     ClassMetadata getClassMetadata() {
145         if (metadata == null) {
146             throw new IllegalStateException JavaDoc(getClassName());
147         }
148         return metadata;
149     }
150
151     @Override JavaDoc
152     public Map JavaDoc<String JavaDoc,RawField> getFields() {
153
154         /*
155          * Lazily create the raw type information. Synchronization is not
156          * required since this object is immutable. If by chance we create two
157          * maps when two threads execute this block, no harm is done. But be
158          * sure to assign the rawFields field only after the map is fully
159          * populated.
160          */

161         if (rawFields == null) {
162             Map JavaDoc<String JavaDoc,RawField> map = new HashMap JavaDoc<String JavaDoc,RawField>();
163             for (RawField field : fields) {
164                 map.put(field.getName(), field);
165             }
166             rawFields = map;
167         }
168         return rawFields;
169     }
170
171     @Override JavaDoc
172     void collectRelatedFormats(Catalog catalog,
173                                Map JavaDoc<String JavaDoc,Format> newFormats) {
174         /* Collect field formats. */
175         for (FieldInfo field : fields) {
176             field.collectRelatedFormats(catalog, newFormats);
177         }
178     }
179
180     @Override JavaDoc
181     void initialize(Catalog catalog) {
182         /* Initialize all fields. */
183         for (FieldInfo field : fields) {
184             field.initialize(catalog);
185         }
186         /* Create the accessor. */
187         Class JavaDoc type = getType();
188         if (type != null) {
189             if (EnhancedAccessor.isEnhanced(type)) {
190                 objAccessor = new EnhancedAccessor(type);
191             } else {
192                 objAccessor = new ReflectionAccessor(catalog, type, fields);
193             }
194         }
195         rawAccessor = new RawAccessor(this, fields);
196     }
197     
198     @Override JavaDoc
199     Object JavaDoc newArray(int len) {
200         return objAccessor.newArray(len);
201     }
202
203     @Override JavaDoc
204     public Object JavaDoc newInstance(EntityInput input, boolean rawAccess) {
205         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
206         return accessor.newInstance();
207     }
208
209     @Override JavaDoc
210     public Object JavaDoc readObject(Object JavaDoc o, EntityInput input, boolean rawAccess) {
211         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
212         accessor.readNonKeyFields(o, input, 0, Accessor.MAX_FIELD_NUM, -1);
213         return o;
214     }
215
216     @Override JavaDoc
217     void writeObject(Object JavaDoc o, EntityOutput output, boolean rawAccess) {
218         Accessor accessor = rawAccess ? rawAccessor : objAccessor;
219         accessor.writeNonKeyFields(o, output);
220     }
221
222     @Override JavaDoc
223     Object JavaDoc convertRawObject(Catalog catalog,
224                             boolean rawAccess,
225                             RawObject rawObject,
226                             IdentityHashMap JavaDoc converted) {
227
228         /*
229          * Synchronization is not required since rawInputFields is immutable.
230          * If by chance we create duplicate values when two threads execute
231          * this block, no harm is done. But be sure to assign the field only
232          * after the values are fully populated.
233          */

234         FieldInfo[] myFields = rawInputFields;
235         if (myFields == null) {
236             myFields = new FieldInfo[fields.size()];
237             fields.toArray(myFields);
238             rawInputFields = myFields;
239         }
240         if (rawObject.getSuper() != null) {
241             throw new IllegalArgumentException JavaDoc
242                 ("RawObject has too many superclasses: " +
243                  rawObject.getType().getClassName());
244         }
245         RawObject[] objects = new RawObject[myFields.length];
246         Arrays.fill(objects, rawObject);
247         EntityInput in = new RawComplexInput
248             (catalog, rawAccess, converted, myFields, objects);
249         Object JavaDoc o = newInstance(in, rawAccess);
250         converted.put(rawObject, o);
251         return readObject(o, in, rawAccess);
252     }
253
254     @Override JavaDoc
255     void skipContents(RecordInput input) {
256         int maxNum = fields.size();
257         for (int i = 0; i < maxNum; i += 1) {
258             fields.get(i).getType().skipContents(input);
259         }
260     }
261
262     @Override JavaDoc
263     void copySecKey(RecordInput input, RecordOutput output) {
264         int maxNum = fields.size();
265         for (int i = 0; i < maxNum; i += 1) {
266             fields.get(i).getType().copySecKey(input, output);
267         }
268     }
269
270     @Override JavaDoc
271     boolean evolve(Format newFormatParam, Evolver evolver) {
272
273         /* Disallow evolution to a non-composite format. */
274         if (!(newFormatParam instanceof CompositeKeyFormat)) {
275             evolver.addEvolveError
276                 (this, newFormatParam, null,
277                  "A composite key class may not be changed to a different " +
278                  "type");
279             return false;
280         }
281         CompositeKeyFormat newFormat = (CompositeKeyFormat) newFormatParam;
282
283         /* Check for added or removed key fields. */
284         if (fields.size() != newFormat.fields.size()) {
285             evolver.addEvolveError
286                 (this, newFormat,
287                  "Composite key class fields were added or removed ",
288                  "Old fields: " + fields +
289                  " new fields: " + newFormat.fields);
290             return false;
291         }
292
293         /* Check for modified key fields. */
294         boolean newVersion = false;
295         for (int i = 0; i < fields.size(); i += 1) {
296             int result = evolver.evolveRequiredKeyField
297                 (this, newFormat, fields.get(i),
298                  newFormat.fields.get(i));
299             if (result == Evolver.EVOLVE_FAILURE) {
300                 return false;
301             }
302             if (result == Evolver.EVOLVE_NEEDED) {
303                 newVersion = true;
304             }
305         }
306
307         /*
308          * We never need to use a custom reader because the physical key field
309          * formats never change. But we do create a new evolved format when
310          * a type changes (primitive <-> primitive wrapper) so that the new
311          * type information is correct.
312          */

313         if (newVersion) {
314             evolver.useEvolvedFormat(this, newFormat, newFormat);
315         } else {
316             evolver.useOldFormat(this, newFormat);
317         }
318         return true;
319     }
320 }
321
Popular Tags