KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > metadata > FetchGroup


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.metadata;
13
14 import com.versant.core.common.Debug;
15 import com.versant.core.common.OID;
16 import com.versant.core.common.State;
17 import com.versant.core.metadata.parser.JdoExtension;
18
19 import java.io.PrintStream JavaDoc;
20 import java.io.Serializable JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Set JavaDoc;
23
24 import com.versant.core.common.BindingSupportImpl;
25
26 /**
27  * A group of fields from a class that are retrieved together. This holds
28  * the field and assorted store specific options.
29  */

30 public final class FetchGroup implements Serializable JavaDoc, Comparable JavaDoc {
31
32     public static final FetchGroupField[] EMPTY_FETCHGROUP_FIELDS = new FetchGroupField[0];
33     public static final int[] EMPTY_INT_ARRAY = new int[0];
34
35     /**
36      * This is the name reserved for the default fetch group.
37      */

38     public static final String JavaDoc DFG_NAME = "default";
39     /**
40      * This is the name reserved for the default fetch group without fake fields.
41      */

42     public static final String JavaDoc DFG_NAME_NO_FAKES = "defaultNoFakes";
43     /**
44      * This is the fetchGroup to load all data.
45      */

46     public static final String JavaDoc RETRIEVE_NAME = "jdoGenieRetrieveFG";
47     /**
48      * This is the fetchGroup to load all columns in the class table.
49      */

50     public static final String JavaDoc ALL_COLS_NAME = "_jdoall";
51     /**
52      * This is the name reserved for the fetch group containing all the
53      * reference and collection fields for reachability searching.
54      */

55     public static final String JavaDoc REF_NAME = "_jdoref";
56     /**
57      * This is the name reserved for the fetch group containing all the
58      * reference fields used to complete one-to-many relationships.
59      */

60     public static final String JavaDoc DETAIL_NAME = "_jdodetail";
61     /**
62      * This is the name reserved for the fetch group containing all the
63      * direct references and dependent fields. All instances in the delete
64      * graph must contain at least this group. This will always be
65      * a superset of the DEP_NAME group.
66      *
67      * @see #DEP_NAME
68      */

69     public static final String JavaDoc DEL_NAME = "_jdodel";
70     /**
71      * This is the name reserved for the fetch group containing all the
72      * depedent reference and collection fields for delete reachability
73      * searching.
74      */

75     public static final String JavaDoc DEP_NAME = "_jdodep";
76     /**
77      * This is the name reserved for the fetch group containing all the
78      * fields that must be filled in the original state (e.g. jdoVersion etc.)
79      * when persisting changes to instances.
80      */

81     public static final String JavaDoc REQ_NAME = "_jdoreq";
82     /**
83      * This is the name reserved for the fetch group containing all the
84      * many-to-many fields that must be cleared when deleting an instance.
85      *
86      * @see ClassMetaData#managedManyToManyFetchGroup
87      */

88     public static final String JavaDoc MANY_TO_MANY_NAME = "_manytomany";
89
90     /**
91      * The name of this group.
92      */

93     public String JavaDoc name;
94     /**
95      * The class this group belongs to.
96      */

97     public ClassMetaData classMetaData;
98     /**
99      * Our index in our classes fetchGroups array. This is -1 for dynamically
100      * created fetch groups as they are not in the fetchGroups array.
101      *
102      * @see ClassMetaData#fetchGroups
103      */

104     public int index = -1;
105     /**
106      * The parsed meta data for this group (null if none i.e. automatically
107      * generated fetch group e.g. the default fetch group).
108      */

109     public JdoExtension extension;
110     /**
111      * The fields in this group in fieldNo order.
112      */

113     public FetchGroupField[] fields;
114     /**
115      * The state field no's of the fetchGroup.
116      */

117     public int[] stateFieldNos;
118     /**
119      * The corresponding fetch group from our superclass or null if none.
120      */

121     public FetchGroup superFetchGroup;
122     /**
123      * The sub fetch groups from our subclasses or null if none.
124      */

125     public FetchGroup[] subFetchGroups;
126     /**
127      * Send any available State data for the instance being fetched along
128      * with the fetch call. This is used for fields that have some data
129      * stored with the instance itself and some data stored elsewhere e.g.
130      * collections on VDS.
131      */

132     public boolean sendFieldsOnFetch;
133     /**
134      * Does this fetch group or any other fetch group in the heirachy
135      * contain any fields with primaryField true?
136      */

137     public boolean hasPrimaryFields;
138     /**
139      * Extra store specific info attached to this fetch group.
140      */

141     public transient StoreFetchGroup storeFetchGroup;
142
143     private boolean canUseParallelFetch;
144     private boolean canUseParallelFetchDone;
145
146     /**
147      * The total number of main table columns in the fetch group.
148      */

149     public int jdbcTotalCols;
150
151     /**
152      * This is a fgf for a jdbc collection field that must be cross joined.
153      * Maps is not supported.
154      */

155     public FetchGroupField crossJoinedCollectionField;
156
157     public FetchGroup(ClassMetaData classMetaData, String JavaDoc name,
158             StoreFetchGroup sfg) {
159         this.classMetaData = classMetaData;
160         this.name = name;
161         this.storeFetchGroup = sfg;
162         if (sfg != null) {
163             sfg.setFetchGroup(this);
164         }
165     }
166
167     /**
168      * Sort by name except for the default fetch group which is always first.
169      * Do not change this ordering.
170      */

171     public int compareTo(Object JavaDoc o) {
172         if (name == DFG_NAME) return -1;
173         return name.compareTo(((FetchGroup)o).name);
174     }
175
176     /**
177      * Add a field to this group. This is used to add fake fields created by
178      * stores to hold extra information (e.g. row version column values for
179      * the JDBC store).
180      */

181     public void add(FieldMetaData fmd) {
182         int n = fields.length;
183         FetchGroupField[] a = new FetchGroupField[n + 1];
184         System.arraycopy(fields, 0, a, 0, n);
185         a[n] = new FetchGroupField(fmd);
186         fields = a;
187         if (storeFetchGroup != null) {
188             storeFetchGroup.fieldAdded(fmd);
189         }
190     }
191
192     /**
193      * Is the field part of this group?
194      */

195     public boolean contains(FieldMetaData fmd) {
196         for (int i = fields.length - 1; i >= 0; i--) {
197             FetchGroupField f = fields[i];
198             if (f.fmd == fmd) return true;
199         }
200         return false;
201     }
202
203     public String JavaDoc toString() {
204         return "FetchGroup@" + System.identityHashCode(this) + ": " + name;
205     }
206
207     /**
208      * Finish initialization of this fetch group.
209      */

210     public void finish() {
211         if (fields != null) {
212             // init the stateFieldNos array
213
int nf = fields.length;
214             stateFieldNos = new int[nf];
215             for (int i = nf - 1; i >= 0; i--) {
216                 stateFieldNos[i] = fields[i].fmd.stateFieldNo;
217             }
218         } else {
219             fields = EMPTY_FETCHGROUP_FIELDS;
220             stateFieldNos = EMPTY_INT_ARRAY;
221         }
222
223         // find the super fetch group (if any)
224
if (name != null) {
225             ClassMetaData pcmd = classMetaData.pcSuperMetaData;
226             if (pcmd != null) {
227                 superFetchGroup = pcmd.getFetchGroup(name);
228             }
229         }
230
231         if (storeFetchGroup != null) {
232             storeFetchGroup.finish();
233         }
234     }
235
236     /**
237      * Get the state fetch group index of this group.
238      *
239      * @see State
240      */

241     public int getStateIndex() {
242         return classMetaData.superFetchGroupCount + index;
243     }
244
245     public boolean isRefFG() {
246         return name.equals("_jdoref");
247     }
248
249     /**
250      * Make sure this fetchGroup is for the available class of OID or one
251      * of its superclasses. Returns the most derived usable group i.e. if
252      * this method is called with a group for class Base and the available
253      * class from the OID is a subclass of base then the corresponding
254      * sub group will be returned.
255      */

256     public FetchGroup resolve(OID oid, ModelMetaData jmd) {
257         // make sure the fetch group is for the available meta data of oid
258
ClassMetaData acmd = oid.getAvailableClassMetaData();
259         ClassMetaData gcmd = classMetaData;
260         if (gcmd == acmd) return this;
261         for (ClassMetaData cmd = acmd; cmd != gcmd;) {
262             cmd = cmd.pcSuperMetaData;
263             if (cmd == null) {
264                 throw BindingSupportImpl.getInstance().internal("Fetch group " + this + " (" + classMetaData +
265                         ") does not match OID " + oid + " (" +
266                         acmd + ")");
267             }
268         }
269         return acmd.getFetchGroup(name);
270     }
271
272     /**
273      * Returns the most derived usable group i.e. if this method is called
274      * with a group for class Base and availableCmd is a subclass of base
275      * then the corresponding sub group will be returned.
276      */

277     public FetchGroup resolve(ClassMetaData availableCmd) {
278         if (availableCmd == classMetaData) return this;
279         return availableCmd.getFetchGroup(name);
280     }
281
282     public void dump() {
283         dump(Debug.OUT, "");
284     }
285
286     public void dump(PrintStream JavaDoc out, String JavaDoc indent) {
287         out.println(indent + "FetchGroup " + this);
288         String JavaDoc is = indent + " ";
289         out.println(is + "classMetaData = " + classMetaData);
290         out.println(is + "index = " + index);
291         out.println(is + "getStateIndex() = " + getStateIndex());
292         out.println(is + "superFetchGroup = " + superFetchGroup);
293         if (subFetchGroups != null) {
294             for (int i = 0; i < subFetchGroups.length; i++) {
295                 FetchGroup sg = subFetchGroups[i];
296                 out.println(is + "subFetchGroups[" + i + "] = " +
297                         sg.classMetaData.qname + " " + sg);
298             }
299         } else {
300             out.println(is + "subFetchGroups is null");
301         }
302         if (fields != null) {
303             for (int i = 0; i < fields.length; i++) {
304                 out.println(is + "fields[" + i + "] " + fields[i]);
305             }
306         }
307         if (stateFieldNos != null) {
308             for (int i = 0; i < stateFieldNos.length; i++) {
309                 out.println(
310                         is + "stateField[" + i + "] no = " + stateFieldNos[i]);
311             }
312         }
313     }
314
315     /**
316      * Can this fetch group make use of parallel fetching of collections
317      * and maps? This will recursively check fetch groups we reference
318      * and so on.
319      */

320     public boolean canUseParallelFetch() {
321         if (canUseParallelFetchDone) return canUseParallelFetch;
322         return canUseParallelFetchImp(new HashSet JavaDoc());
323     }
324
325     private boolean canUseParallelFetchImp(Set JavaDoc fgs) {
326         if (fgs.contains(this)) return canUseParallelFetch;
327
328         fgs.add(this);
329         for (int i = fields.length - 1; i >= 0; i--) {
330             FetchGroupField fgf = fields[i];
331             int cat = fgf.fmd.category;
332             if (cat == MDStatics.CATEGORY_COLLECTION
333                     || cat == MDStatics.CATEGORY_MAP) {
334                 canUseParallelFetch = true;
335                 break;
336             } else if (cat == MDStatics.CATEGORY_REF
337                     && fgf.nextFetchGroup.canUseParallelFetchImp(fgs)) {
338                 canUseParallelFetch = true;
339                 break;
340             }
341         }
342         //give the superclass fg a change to calculate
343
if (superFetchGroup != null) {
344             superFetchGroup.canUseParallelFetchImp(fgs);
345             //if we are false then take superfetch groups property
346
if (!canUseParallelFetch) canUseParallelFetch = superFetchGroup.canUseParallelFetch;
347         }
348
349         canUseParallelFetchDone = true;
350         return canUseParallelFetch;
351     }
352
353     /**
354      * Does this fetch group or any of its sub fetch groups contain any
355      * fields with secondaryField true?
356      */

357     public boolean hasSecondaryFields() {
358         if (fields != null) {
359             for (int i = fields.length - 1; i >= 0; i--) {
360                 if (fields[i].fmd.secondaryField) return true;
361             }
362         }
363         if (subFetchGroups != null) {
364             for (int i = subFetchGroups.length - 1; i >= 0; i--) {
365                 if (subFetchGroups[i].hasSecondaryFields()) return true;
366             }
367         }
368         return false;
369     }
370
371     /**
372      * Does this fetch group or any of its sub fetch groups contain any
373      * fields with primaryField true? This will search the heirachy i.e.
374      * it does not check the hasPrimaryFields flag. If nonFake is true then
375      * only fields with fake == true are not considered.
376      */

377     public boolean hasPrimaryFields(boolean nonFake) {
378         if (fields == null) return false;
379         for (int i = fields.length - 1; i >= 0; i--) {
380             final FieldMetaData fmd = fields[i].fmd;
381             if (fmd.primaryField && (!nonFake || !fmd.fake)) {
382                 return true;
383             }
384         }
385         if (subFetchGroups != null) {
386             for (int i = subFetchGroups.length - 1; i >= 0; i--) {
387                 if (subFetchGroups[i].hasPrimaryFields(false)) {
388                     return true;
389                 }
390             }
391         }
392         return false;
393     }
394
395     /**
396      * Set the sendFieldsOnFetch flag for us and all of our sub
397      * fetch groups recursively.
398      */

399     public void setSendFieldsOnFetch(boolean on) {
400         this.sendFieldsOnFetch = on;
401         if (subFetchGroups != null) {
402             for (int i = subFetchGroups.length - 1; i >= 0; i--) {
403                 subFetchGroups[i].setSendFieldsOnFetch(on);
404             }
405         }
406     }
407
408     /**
409      * Set the hasPrimaryFields flag on us and all of our sub fetch groups
410      * recursively.
411      */

412     public void setHasPrimaryFields(boolean on) {
413         this.hasPrimaryFields = on;
414         if (subFetchGroups != null) {
415             for (int i = subFetchGroups.length - 1; i >= 0; i--) {
416                 subFetchGroups[i].setHasPrimaryFields(on);
417             }
418         }
419     }
420 }
421
422
Popular Tags