KickJava   Java API By Example, From Geeks To Geeks.

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


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.metadata.parser.JdoElement;
16 import com.versant.core.metadata.parser.JdoExtension;
17 import com.versant.core.metadata.parser.JdoExtensionKeys;
18
19 import java.util.*;
20
21 import com.versant.core.common.BindingSupportImpl;
22
23 /**
24  * This is used by MetaDataBuilder to construct fetch groups. Putting all
25  * the fetch group stuff in one file should add some much needed sanity.
26  */

27 public class FetchGroupBuilder {
28
29     private final ModelMetaData jmd;
30     private final boolean sendCurrentForFGWithSecFields;
31     private final boolean readObjectBeforeWrite;
32
33     public FetchGroupBuilder(ModelMetaData jmd,
34             boolean sendCurrentForFGWithSecFields, boolean readObjectBeforeWrite) {
35         this.jmd = jmd;
36         this.sendCurrentForFGWithSecFields = sendCurrentForFGWithSecFields;
37         this.readObjectBeforeWrite = readObjectBeforeWrite;
38     }
39
40     protected StoreFetchGroup createStoreFetchGroup() {
41         return null;
42     }
43
44     /**
45      * Return the first fetch-group extension in a or null if none.
46      */

47     public JdoExtension findFetchGroupExt(JdoExtension[] a) {
48         if (a == null) return null;
49         int n = a.length;
50         for (int i = 0; i < n; i++) {
51             if (a[i].key == JdoExtensionKeys.FETCH_GROUP) return a[i];
52         }
53         return null;
54     }
55
56     /**
57      * Build all the fetch groups. This must be called once all the fields for
58      * each class have been created (including fake fields etc.).
59      */

60     public void buildFetchGroups(boolean quiet) {
61         ClassMetaData[] classes = jmd.classes;
62         int clen = classes.length;
63
64         // create all the groups with their field arrays
65
if (Debug.DEBUG) System.out.println("MDB-FGB: Creating fetch groups");
66         for (int i = 0; i < clen; i++) {
67             ClassMetaData cmd = classes[i];
68             try {
69                 if (cmd.pcSuperMetaData == null) createFetchGroups(cmd, quiet);
70             } catch (RuntimeException JavaDoc e) {
71                 cmd.addError(e, quiet);
72             }
73         }
74
75         // resolve next-fetch-group references etc
76
if (Debug.DEBUG) {
77             System.out.println(
78                     "MDB-FGB: Resolving next-fetch-group references");
79         }
80         for (int i = 0; i < clen; i++) {
81             ClassMetaData cmd = classes[i];
82             try {
83                 processFetchGroups(cmd);
84             } catch (RuntimeException JavaDoc e) {
85                 cmd.addError(e, quiet);
86             }
87         }
88
89         // Set the sendFieldsOnFetch on FetchGroup's with secondaryField's
90
// if required by the DataStore for the class. Also sets the
91
// hasPrimaryFields flag on all FetchGroups.
92
for (int i = 0; i < clen; i++) {
93             ClassMetaData cmd = classes[i];
94             // todo Commenting out these lines appeared to make no difference
95
// if (cmd.pcSuperMetaData != null && cmd.vdsClass == null) {
96
// continue;
97
// }
98
FetchGroup[] fetchGroups = cmd.fetchGroups;
99             if (fetchGroups == null) {
100                 continue;
101             }
102             for (int j = fetchGroups.length - 1; j >= 0; j--) {
103                 FetchGroup fg = fetchGroups[j];
104                 if (sendCurrentForFGWithSecFields && !fg.hasPrimaryFields(true)
105                         && fg.hasSecondaryFields()) {
106                     fg.setSendFieldsOnFetch(true);
107                 }
108                 if (fg.hasPrimaryFields(false)) {
109                     fg.setHasPrimaryFields(true);
110                 }
111             }
112         }
113     }
114
115     /**
116      * Create all groups for cmd with their field arrays and then recursively
117      * create groups for its subclasses.
118      */

119     private void createFetchGroups(ClassMetaData cmd, boolean quiet) {
120         if (cmd.fields == null) {
121             return; // no fields due to some previous error
122
}
123
124         ArrayList groups = cmd.fgTmp = new ArrayList();
125         HashMap nameGroupMap = cmd.nameGroupMap = new HashMap();
126
127         FetchGroup dfg = createDefaultFetchGroup(cmd);
128         groups.add(dfg);
129         nameGroupMap.put(dfg.name, dfg);
130
131         FetchGroup retrieveFG = createRetrieveFetchGroup(cmd);
132         groups.add(retrieveFG);
133         nameGroupMap.put(retrieveFG.name, retrieveFG);
134
135         FetchGroup allColsFG = createAllColumnsFetchGroup(cmd);
136         groups.add(allColsFG);
137         nameGroupMap.put(allColsFG.name, allColsFG);
138
139         FetchGroup dfgNoFakes = createFetchGroupDefaultNoFakes(cmd);
140         groups.add(dfgNoFakes);
141         nameGroupMap.put(dfgNoFakes.name, dfgNoFakes);
142
143         // if you add new groups here add a corresponding line to the block
144
// towards the end of this method that caches special groups in
145
// ClassMetaData
146
addNotNull(createRefFetchGroup(cmd), groups, nameGroupMap);
147         addNotNull(createDepFetchGroup(cmd), groups, nameGroupMap);
148         addNotNull(createReqFetchGroup(cmd), groups, nameGroupMap);
149         addNotNull(createManagedManyToManyFetchGroup(cmd), groups,
150                 nameGroupMap);
151
152         // find all the user defined groups
153
JdoElement[] elements = cmd.jdoClass.elements;
154         int elementsLen = elements.length;
155         for (int j = 0; j < elementsLen; j++) {
156             JdoElement element = elements[j];
157             if (!(element instanceof JdoExtension)) continue;
158             JdoExtension e = (JdoExtension)element;
159             if (e.key != JdoExtensionKeys.FETCH_GROUP) continue;
160             FetchGroup g = new FetchGroup(cmd, e.getString(), createStoreFetchGroup());
161             try {
162                 if (g.name.equals(FetchGroup.DFG_NAME)) {
163                     throw BindingSupportImpl.getInstance().runtime("The group name '" + FetchGroup.DFG_NAME +
164                             "' is reserved for the " +
165                             "default fetch group\n" + e.getContext());
166                 }
167                 if (g.name.equals(FetchGroup.REF_NAME)) {
168                     throw BindingSupportImpl.getInstance().runtime("The group name '" + FetchGroup.REF_NAME +
169                             "' is reserved internal use\n" +
170                             e.getContext());
171                 }
172                 if (nameGroupMap.containsKey(g.name)) {
173                     throw BindingSupportImpl.getInstance().runtime("There is already a group called: '" + g.name + "'\n" +
174                             e.getContext());
175                 }
176                 nameGroupMap.put(g.name, g);
177                 g.extension = e;
178                 processFetchGroupFields(cmd, g, quiet);
179                 groups.add(g);
180             } catch (RuntimeException JavaDoc e1) {
181                 cmd.addError(e1, quiet);
182             }
183         }
184
185         // create an empty group for each group from our parent class that
186
// has not been extended i.e. group defined here with same name
187
if (cmd.pcSuperMetaData != null) {
188             List list = cmd.pcSuperMetaData.fgTmp;
189             for (int i = 0; i < list.size(); i++) {
190                 FetchGroup sg = (FetchGroup)list.get(i);
191                 if (nameGroupMap.containsKey(sg.name)) continue;
192                 FetchGroup g = new FetchGroup(cmd, sg.name, createStoreFetchGroup());
193                 g.fields = new FetchGroupField[0];
194                 groups.add(g);
195                 nameGroupMap.put(g.name, g);
196             }
197         }
198
199         // Fill in the fetchGroup for all fields creating new groups for fields
200
// without a group that are not in the default fetch group. If the
201
// field is a pass1 field then the optimistic locking field (if any)
202
// is included in the group.
203
FieldMetaData[] fields = cmd.fields;
204         int fieldsLen = fields.length;
205         for (int i = 0; i < fieldsLen; i++) {
206             FieldMetaData fmd = fields[i];
207             if (fmd.jdoField != null && fmd.jdoField.extensions != null) {
208                 try {
209                     JdoExtension e = findFetchGroupExt(fmd.jdoField.extensions);
210                     if (e != null) {
211                         String JavaDoc gname = e.getString();
212                         fmd.fetchGroup = (FetchGroup)nameGroupMap.get(gname);
213                         if (fmd.fetchGroup == null) {
214                             throw BindingSupportImpl.getInstance().runtime("No such fetch-group: '" + gname + "'\n" +
215                                     e.getContext());
216                         }
217                     }
218                 } catch (RuntimeException JavaDoc e1) {
219                     fmd.addError(e1, quiet);
220                 }
221             }
222             if (fmd.fetchGroup == null) {
223                 if (fmd.defaultFetchGroup) {
224                     fmd.fetchGroup = dfg;
225                 } else {
226                     String JavaDoc name = "_" + fmd.name + cmd.qname;
227                     for (int j = 2; nameGroupMap.containsKey(name); j++) {
228                         name = "_" + fmd.name + j;
229                     }
230                     FetchGroup g = new FetchGroup(cmd, name, createStoreFetchGroup());
231
232                     ArrayList a = new ArrayList();
233                     if (fmd.isEmbeddedRef()) {
234                         //must add the fake fields to the fg
235
if (fmd.embeddedFmds != null) {
236                             for (int j = 0; j < fmd.embeddedFmds.length; j++) {
237                                 FieldMetaData embeddedFmd = fmd.embeddedFmds[j];
238                                 a.add(new FetchGroupField(embeddedFmd));
239                             }
240                         }
241                     } else {
242                         FetchGroupField fgf = createFetchGroupFieldWithPrefetch(fmd);
243                         a.add(fgf);
244                     }
245
246                     // classes with storeAllFields set also read all fields
247
// so there is no need to add the optimistic locking field
248
// to fetch groups
249
if (fmd.primaryField && !cmd.storeAllFields
250                             && cmd.optimisticLockingField != null) {
251                         a.add(new FetchGroupField(cmd.optimisticLockingField));
252                     }
253
254                     g.fields = new FetchGroupField[a.size()];
255                     a.toArray(g.fields);
256
257                     groups.add(g);
258                     nameGroupMap.put(g.name, g);
259                     fmd.fetchGroup = g;
260                 }
261             }
262         }
263
264         // dig out some popular fetchgroups for quick access
265
cmd.refFetchGroup = (FetchGroup)nameGroupMap.get(FetchGroup.REF_NAME);
266         cmd.depFetchGroup = (FetchGroup)nameGroupMap.get(FetchGroup.DEP_NAME);
267         cmd.reqFetchGroup = (FetchGroup)nameGroupMap.get(FetchGroup.REQ_NAME);
268         cmd.managedManyToManyFetchGroup = (FetchGroup)nameGroupMap.get(
269                 FetchGroup.MANY_TO_MANY_NAME);
270
271         // process all of our subclasses
272
ClassMetaData[] pcSubclasses = cmd.pcSubclasses;
273         if (pcSubclasses != null) {
274             for (int i = pcSubclasses.length - 1; i >= 0; i--) {
275                 createFetchGroups(cmd.pcSubclasses[i], quiet);
276             }
277         }
278
279         if (cmd.pcSuperMetaData == null) {
280             Collections.sort(cmd.fgTmp);
281             if (cmd.pcSubclasses != null) {
282                 doSubFGs(cmd);
283             }
284
285         }
286
287         if (cmd.pcSuperMetaData == null) {
288             createFGArrays(cmd);
289         }
290     }
291
292     /**
293      * Create a FGF for a field with prefetching enabled if that makes sense
294      * for the store.
295      */

296     protected FetchGroupField createFetchGroupFieldWithPrefetch(
297             FieldMetaData fmd) {
298         return new FetchGroupField(fmd);
299     }
300
301     private void addNotNull(FetchGroup g, ArrayList groups,
302             HashMap nameGroupMap) {
303         if (g != null) {
304             groups.add(g);
305             nameGroupMap.put(g.name, g);
306         }
307     }
308
309     private void doSubFGs(ClassMetaData cmd) {
310         ClassMetaData[] subCmds = cmd.pcSubclasses;
311         if (subCmds == null) return;
312         ArrayList list = new ArrayList();
313         for (int i = 0; i < subCmds.length; i++) {
314             ClassMetaData subCmd = subCmds[i];
315             Collections.sort(subCmd.fgTmp);
316             list.clear();
317             for (int j = 0; j < cmd.fgTmp.size(); j++) {
318                 FetchGroup fetchGroup = (FetchGroup)cmd.fgTmp.get(j);
319                 FetchGroup subFG = (FetchGroup)subCmd.nameGroupMap.get(
320                         fetchGroup.name);
321                 if (j == 0) {
322                     if (!fetchGroup.name.equals(FetchGroup.DFG_NAME) || !subFG.name.equals(
323                             FetchGroup.DFG_NAME)) {
324                         throw BindingSupportImpl.getInstance().internal(
325                                 "DFG broken");
326                     }
327                 }
328                 list.add(subFG);
329             }
330             subCmd.fgTmp.removeAll(list);
331             list.addAll(subCmd.fgTmp);
332             subCmd.fgTmp.clear();
333             subCmd.fgTmp.addAll(list);
334             doSubFGs(subCmd);
335         }
336     }
337
338     private void createFGArrays(ClassMetaData cmd) {
339         indexFGs(cmd);
340         ClassMetaData[] cmds = cmd.pcSubclasses;
341         if (cmds == null) return;
342         for (int i = 0; i < cmds.length; i++) {
343             ClassMetaData aCmd = cmds[i];
344             createFGArrays(aCmd);
345         }
346     }
347
348     private void indexFGs(ClassMetaData cmd) {
349         int ng = cmd.fgTmp.size();
350         FetchGroup[] fga = cmd.fetchGroups = new FetchGroup[ng];
351         FetchGroup[] sfga = cmd.sortedFetchGroups = new FetchGroup[ng];
352         cmd.fgTmp.toArray(fga);
353         cmd.fgTmp.toArray(sfga);
354         Arrays.sort(sfga);
355         for (int i = fga.length - 1; i >= 0; i--) {
356             if (fga[i].index == -1) {
357                 fga[i].index = i;
358             }
359         }
360     }
361
362     /**
363      * Create the default fetch group for cmd.
364      */

365     private FetchGroup createDefaultFetchGroup(ClassMetaData cmd) {
366         FieldMetaData[] fields = cmd.fields;
367         FetchGroup g = new FetchGroup(cmd, FetchGroup.DFG_NAME, createStoreFetchGroup());
368         int n = fields.length;
369         ArrayList a = new ArrayList(n);
370         for (int i = 0; i < n; i++) {
371             FieldMetaData fmd = fields[i];
372             if (!fmd.defaultFetchGroup || fmd.primaryKey) continue;
373             FetchGroupField fgf = new FetchGroupField(fmd);
374             a.add(fgf);
375         }
376         n = a.size();
377         g.fields = new FetchGroupField[n];
378         a.toArray(g.fields);
379         return g;
380     }
381
382     /**
383      * This creates a fetch group that contains only default fetch group fields
384      * but no fake fields must be added here.
385      */

386     private FetchGroup createFetchGroupDefaultNoFakes(ClassMetaData cmd) {
387         FetchGroup g = new FetchGroup(cmd, FetchGroup.DFG_NAME_NO_FAKES, createStoreFetchGroup());
388         FieldMetaData[] fields = cmd.fields;
389         int n = fields.length;
390         ArrayList a = new ArrayList(n);
391         for (int i = 0; i < n; i++) {
392             FieldMetaData fmd = fields[i];
393             if (fmd.defaultFetchGroup && !fmd.fake) {
394                 FetchGroupField fgf = new FetchGroupField(fmd);
395                 a.add(fgf);
396             }
397         }
398         n = a.size();
399         g.fields = new FetchGroupField[n];
400         a.toArray(g.fields);
401         return g;
402     }
403
404     /**
405      * Create the retrieve fetch group for cmd.
406      */

407     private FetchGroup createRetrieveFetchGroup(ClassMetaData cmd) {
408         FetchGroup g = new FetchGroup(cmd, FetchGroup.RETRIEVE_NAME, createStoreFetchGroup());
409         FieldMetaData[] fields = cmd.fields;
410         int n = fields.length;
411         ArrayList a = new ArrayList(n);
412         for (int i = 0; i < n; i++) {
413             FieldMetaData fmd = fields[i];
414             if (fmd.persistenceModifier != MDStatics.PERSISTENCE_MODIFIER_PERSISTENT) continue;
415             FetchGroupField fgf = createFetchGroupFieldWithPrefetch(fmd);
416             a.add(fgf);
417         }
418         n = a.size();
419         g.fields = new FetchGroupField[n];
420         a.toArray(g.fields);
421         return g;
422     }
423
424     /**
425      * Create the all columns fetch group for cmd. This implementation just
426      * creates a dummy empty fetch group.
427      */

428     protected FetchGroup createAllColumnsFetchGroup(ClassMetaData cmd) {
429         FetchGroup g = new FetchGroup(cmd, FetchGroup.ALL_COLS_NAME, createStoreFetchGroup());
430         g.fields = new FetchGroupField[0];
431         return g;
432     }
433
434     /**
435      * Create the ref fetch group for cmd or return null if cmd does not
436      * have any fields that reference other objects. Polyref and collection
437      * fields are included. This does not fill in the nextFetchGroup and
438      * nextKeyFetchGroup for the fields as this can only be done once all
439      * the groups have been created.
440      */

441     private FetchGroup createRefFetchGroup(ClassMetaData cmd) {
442         FieldMetaData[] fields = cmd.fields;
443         int n = fields.length;
444         ArrayList a = new ArrayList(n);
445         for (int i = 0; i < n; i++) {
446             FieldMetaData fmd = fields[i];
447             if (fmd.isDirectRef() && fmd.isFake() && fmd.inverseFieldMetaData != null) {
448                 continue;
449             }
450             switch (fmd.category) {
451                 case MDStatics.CATEGORY_POLYREF:
452                     a.add(new FetchGroupField(fmd));
453                     break;
454                 case MDStatics.CATEGORY_COLLECTION:
455                 case MDStatics.CATEGORY_MAP:
456                     if (fmd.elementType == Object JavaDoc.class
457                             || fmd.keyType == Object JavaDoc.class
458                             || (fmd.elementType != null && fmd.elementType.isInterface())
459                             || (fmd.keyType != null && fmd.keyType.isInterface())) {
460                         a.add(new FetchGroupField(fmd));
461                         break;
462                     }
463                 default:
464                     ClassMetaData refmd = fmd.getRefOrValueClassMetaData();
465                     if (refmd != null || fmd.keyTypeMetaData != null) {
466                         a.add(new FetchGroupField(fmd));
467                     }
468             }
469         }
470         n = a.size();
471         if (n == 0) {
472             return null;
473         }
474         FetchGroup g = new FetchGroup(cmd, FetchGroup.REF_NAME, createStoreFetchGroup());
475         g.fields = new FetchGroupField[n];
476         a.toArray(g.fields);
477         return g;
478     }
479
480     /**
481      * Create the dependent fetch group for cmd or return null if cmd does not
482      * have any fields that reference dependent objects. This does not fill
483      * in the nextFetchGroup and nextKeyFetchGroup for the fields as this can
484      * only be done once all the groups have been created.
485      */

486     private FetchGroup createDepFetchGroup(ClassMetaData cmd) {
487         FieldMetaData[] fields = cmd.fields;
488         int n = fields.length;
489         ArrayList a = new ArrayList(n);
490         for (int i = 0; i < n; i++) {
491             FieldMetaData fmd = fields[i];
492             if (!fmd.dependentValues && !fmd.dependentKeys) continue;
493             if (fmd.category != MDStatics.CATEGORY_POLYREF) {
494                 ClassMetaData refmd = fmd.getRefOrValueClassMetaData();
495                 if (refmd == null && fmd.keyTypeMetaData == null) continue;
496             }
497             a.add(new FetchGroupField(fmd));
498         }
499         n = a.size();
500         if (n == 0) return null;
501         FetchGroup g = new FetchGroup(cmd, FetchGroup.DEP_NAME, createStoreFetchGroup());
502         g.fields = new FetchGroupField[n];
503         a.toArray(g.fields);
504         return g;
505     }
506
507     /**
508      * Create the fetch group containing required all the fields that must
509      * be filled in the original state when persisting changes to instances.
510      * This includes all autoset version fields ans well as autoset timestamp
511      * fields used to implement optimistic locking.
512      */

513     private FetchGroup createReqFetchGroup(ClassMetaData cmd) {
514         FieldMetaData[] fields = cmd.fields;
515         int n = fields.length;
516         ArrayList a = new ArrayList(n);
517         if (readObjectBeforeWrite) {
518             for (int i = 0; i < n; i++) {
519                 FieldMetaData fmd = fields[i];
520                 if (fmd.primaryField) {
521                     FetchGroupField fgf = new FetchGroupField(fmd);
522                     fgf.doNotFetchObject = true;
523                     a.add(fgf);
524                 }
525             }
526         } else {
527             for (int i = 0; i < n; i++) {
528                 FieldMetaData fmd = fields[i];
529                 if (isReqField(cmd, fmd)) {
530                     a.add(new FetchGroupField(fmd));
531                 }
532             }
533         }
534         n = a.size();
535         if (n == 0) return null;
536         FetchGroup g = new FetchGroup(cmd, FetchGroup.REQ_NAME, createStoreFetchGroup());
537         g.fields = new FetchGroupField[n];
538         a.toArray(g.fields);
539         return g;
540     }
541
542     /**
543      * Is fmd required before changes to an instance can be persisted?
544      */

545     private boolean isReqField(ClassMetaData cmd, FieldMetaData fmd) {
546         if (fmd.autoSet == MDStatics.AUTOSET_NO) {
547             return false;
548         }
549         if (fmd.typeCode == MDStatics.DATE) {
550             return fmd == cmd.optimisticLockingField;
551         }
552         return true;
553     }
554
555     /**
556      * Create the fetch group containing all the managed many-to-many fields
557      * and all the required fields. No group is created if there are no
558      * managed many-to-many fields.
559      */

560     private FetchGroup createManagedManyToManyFetchGroup(ClassMetaData cmd) {
561         int manyToManyCount = 0;
562         FieldMetaData[] fields = cmd.fields;
563         int n = fields.length;
564         ArrayList a = new ArrayList(n);
565         for (int i = 0; i < n; i++) {
566             FieldMetaData fmd = fields[i];
567             if (fmd.isManyToMany && fmd.managed || isReqField(cmd, fmd)) {
568                 if (fmd.isManyToMany) manyToManyCount++;
569                 a.add(new FetchGroupField(fmd));
570             }
571         }
572         if (manyToManyCount == 0) return null;
573         FetchGroup g = new FetchGroup(cmd, FetchGroup.MANY_TO_MANY_NAME, createStoreFetchGroup());
574         g.fields = new FetchGroupField[a.size()];
575         a.toArray(g.fields);
576         return g;
577     }
578
579     /**
580      * Process the groups extension to find all of its fields. This does
581      * not resolve next-fetch-group extensions as this can only be done
582      * when all groups have been created.
583      */

584     private void processFetchGroupFields(ClassMetaData cmd, FetchGroup g,
585             boolean quite) {
586         JdoExtension e = g.extension;
587         HashSet fieldNameSet = new HashSet(17);
588         ArrayList fields = new ArrayList();
589         JdoExtension[] nested = e.nested;
590         if (nested == null) return;
591         int nn = nested.length;
592         boolean noFgFields = true;
593         for (int k = 0; k < nn; k++) {
594             JdoExtension ne = nested[k];
595             if (ne.key != JdoExtensionKeys.FIELD_NAME) continue;
596             String JavaDoc fname = ne.getString();
597             if (fieldNameSet.contains(fname)) {
598                 throw BindingSupportImpl.getInstance().runtime("Field is already in group: '" + fname + "'\n" +
599                         ne.getContext());
600             }
601             noFgFields = false;
602             //don't add pk fields to fg's
603
FieldMetaData fmd = cmd.getFieldMetaData(fname);
604             if (fmd == null) {
605                 cmd.addError(BindingSupportImpl.getInstance().runtime("Field does not exist: '" + fname + "'\n" +
606                         ne.getContext()), quite);
607                 continue;
608             }
609             if (fmd.primaryKey) continue;
610 // if (fmd.jdbcField.isSharedWithPK()) continue;
611

612
613             fieldNameSet.add(fname);
614             FetchGroupField f = new FetchGroupField(fmd);
615             f.extension = ne;
616             fields.add(f);
617         }
618
619
620         //add the fields that should be in all the fg's
621
FieldMetaData[] fmds = cmd.fields;
622         int n = fmds.length;
623         for (int i = 0; i < n; i++) {
624             FieldMetaData fmd = fmds[i];
625             if (!fmd.secondaryField && fmd.includeInAllFGs() && !fieldNameSet.contains(
626                     fmd.name)) {
627                 fieldNameSet.add(fmd.name);
628                 FetchGroupField fgf = new FetchGroupField(fmd);
629                 fields.add(fgf);
630             }
631         }
632
633         int nf = fields.size();
634         if (noFgFields && nf == 0) {
635             throw BindingSupportImpl.getInstance().runtime("Fetch group does not contain any fields: '" + g.name + "'\n" +
636                     e.getContext());
637         }
638         g.fields = new FetchGroupField[nf];
639         fields.toArray(g.fields);
640     }
641
642     /**
643      * Process extensions for all fields in all groups. This resolves
644      * next-fetch-group and next-key-fetch-group references.
645      */

646     private void processFetchGroups(ClassMetaData cmd) {
647         processRefFetchGroup(cmd);
648         FetchGroup[] groups = cmd.fetchGroups;
649         if (groups == null) {
650             return;
651         }
652         FetchGroup dep = cmd.refFetchGroup;
653         int ng = groups.length;
654         for (int i = 0; i < ng; i++) {
655             FetchGroup group = groups[i];
656             if (group == dep) continue;
657             FetchGroupField[] fields = group.fields;
658             if (fields == null) continue;
659             int nf = fields.length;
660             for (int j = 0; j < nf; j++) {
661                 FetchGroupField f = fields[j];
662                 ClassMetaData refmd = f.fmd.getRefOrValueClassMetaData();
663                 ClassMetaData keymd = f.fmd.keyTypeMetaData;
664                 JdoExtension[] nested = f.extension == null ? null : f.extension.nested;
665                 if (nested != null) {
666                     int nl = nested.length;
667                     for (int k = 0; k < nl; k++) {
668                         JdoExtension e = nested[k];
669                         switch (e.key) {
670                             case JdoExtensionKeys.NEXT_FETCH_GROUP:
671                                 processNextFetchGroup(f, e, refmd);
672                                 break;
673                             case JdoExtensionKeys.NEXT_KEY_FETCH_GROUP:
674                                 processNextKeyFetchGroup(f, e, keymd);
675                                 break;
676                             default:
677                                 if (e.isCommon()) {
678                                     MetaDataBuilder.throwUnexpectedExtension(e);
679                                 }
680                         }
681                         ;
682                     }
683                 }
684                 if (f.nextFetchGroup == null && refmd != null && refmd.fetchGroups != null) {
685                     f.nextFetchGroup = refmd.fetchGroups[0];
686                 }
687                 if (f.nextKeyFetchGroup == null && keymd != null && keymd.fetchGroups != null) {
688                     f.nextKeyFetchGroup = keymd.fetchGroups[0];
689                 }
690             }
691         }
692     }
693
694     private void processNextFetchGroup(FetchGroupField f, JdoExtension e,
695             ClassMetaData refmd) {
696         if (f.nextFetchGroup != null) {
697             throw BindingSupportImpl.getInstance().runtime("Only one next-fetch-group extension is allowed\n" +
698                     e.getContext());
699         }
700         if (refmd == null) {
701             throw BindingSupportImpl.getInstance().runtime("Field does not reference a PC class\n" +
702                     e.getContext());
703         }
704         FetchGroup g = refmd.getFetchGroup(e.getString());
705         if (g == null) {
706             throw BindingSupportImpl.getInstance().runtime("Fetch group '" + e.getString() + "' not found in class " +
707                     refmd.qname + "\n" +
708                     e.getContext());
709         }
710         f.nextFetchGroup = g;
711     }
712
713     private void processNextKeyFetchGroup(FetchGroupField f, JdoExtension e,
714             ClassMetaData keymd) {
715         if (f.nextKeyFetchGroup != null) {
716             throw BindingSupportImpl.getInstance().runtime("Only one next-key-fetch-group extension is allowed\n" +
717                     e.getContext());
718         }
719         if (keymd == null) {
720             throw BindingSupportImpl.getInstance().runtime("Field key does not reference a PC class\n" +
721                     e.getContext());
722         }
723         FetchGroup g = keymd.getFetchGroup(e.getString());
724         if (g == null) {
725             throw BindingSupportImpl.getInstance().runtime("Fetch group '" + e.getString() + "' not found in class " +
726                     keymd.qname + "\n" +
727                     e.getContext());
728         }
729         f.nextKeyFetchGroup = g;
730     }
731
732     /**
733      * Fill in the nextFetchGroup and nextKeyFetchGroup references for
734      * all the fields in the refFetchGroup for cmd (if any). Only dependent
735      * object references are followed.
736      */

737     private void processRefFetchGroup(ClassMetaData cmd) {
738         FetchGroup g = cmd.refFetchGroup;
739         if (g == null) return;
740         FetchGroupField[] fields = g.fields;
741         int nf = fields.length;
742         for (int j = 0; j < nf; j++) {
743             FetchGroupField f = fields[j];
744             FieldMetaData fmd = f.fmd;
745             // only follow dependent object references for this group
746
if (fmd.dependentValues) {
747                 ClassMetaData refmd = fmd.getRefOrValueClassMetaData();
748                 if (refmd != null) f.nextFetchGroup = refmd.refFetchGroup;
749             }
750             if (fmd.dependentKeys) {
751                 ClassMetaData keymd = fmd.keyTypeMetaData;
752                 if (keymd != null) f.nextKeyFetchGroup = keymd.refFetchGroup;
753             }
754         }
755     }
756 }
757
Popular Tags